Set Multi Tenant in Active Admin Controllers (required for Searchkick index) - activeadmin

I am using Active Admin in my multi tenant app. I also use Searchkick which has a custom tenant specific index in each model:
class Budget < ApplicationRecord
multi_tenant :company
searchkick inheritance: true,index_name: -> { [MultiTenant.current_tenant.tenant_name, model_name.plural, Rails.env].join('_') }
end
The issue is that in AA this logic fails because on the tenant is set. I want to be able to set this in AA when updating a record.
For example I would update http://localhost:4000/admin/budgets/dt2kqvgm where dt2kqvgm is the Friendly ID of the record. So I want to call something like:
MultiTenant.current_tenant = Budget.friendly.find(params['budget']['company_id'])
when I create / update a record etc.
Currently I get:
undefined method `tenant_name' for nil:NilClass
because in my application controller the tenant is set based on the user authentication to scope the current company etc. In AA I want/ need to set this based on the params which it seems you can't access from the AA controller logic. My params look like this in AA:
{"utf8"=>"✓", "_method"=>"patch", "authenticity_token"=>"PrhNGnPvV1Qfb5RCwTVv4Wwz9tjf9SFy2VWDcyJXoFLytM8y5ZAyF7h8I7xa+fy01E9Fc/v2CvR52I4/LKOLHQ==", "budget"=>{"company_id"=>"9", "name"=>"qweqwe", "description"=>"qweqwe", "notes"=>"qwee", "flag_active"=>"1", "slug"=>"dt2kqvgm", "title"=>"qweqwe"}, "commit"=>"Update Budget", "controller"=>"admin/budgets", "action"=>"update", "id"=>"dt2kqvgm"}

I don't know if this is the best way to do this but it works. I am know it needs tweaks but it's a start - you needs to:
set an around_action filter
add permitted_params
around_action :set_tenant, only: :update
controller do
def set_tenant
MultiTenant.with(Company.find(resource.company_id)) do
yield
end
end
def permitted_params
params.permit location: %[ company_id ]
end
end
It would seem this is required for each controller. Perhaps there is a way to add this as a default AA filter?
I also added the filter to just the update action.

Related

How does one access an Extension to a table in Acumatica Business Logic

Apologies if this question has been answered elsewhere, I have had trouble finding any resources on this.
The scenario is this. I have created a custom field in the Tax Preferences screen called Usrapikey.
This value holds an api key for a call that gets done in some custom business logic.
The custom business logic however occurs on the Taxes screen.
So within the event handler I need to access that API key value from the other screen. I have tried instantiating graphs and using linq and bql but to no avail.
below is what I have currently and my error is: No overload for method 'GetExtension' takes 1 arguments
If I am going about this the wrong way please let me know if there is a more civilized way to do this
protected virtual void _(Events.FieldUpdated<TaxRev, TaxRev.startDate> e)
{
var setup = PXGraph.CreateInstance<TXSetupMaint>();
var TXSetupEX = setup.GetExtension<PX.Objects.TX.TXSetupExt>(setup);
var rateObj = GetValues(e.Row.TaxID, TXSetupEX.Usrapikey);
decimal rate;
var tryRate = (Decimal.TryParse(rateObj.rate.combined_rate, out rate));
row.TaxRate = (decimal)rate * (decimal)100;
row.TaxBucketID = 1;
}
Many Thanks!
Well, acumatica support got back. It seems if you want to access the base page use:
TXSetup txsetup = PXSetup<TXSetup>.Select(Base);
To get the extension use:
TXSetupExt rowExt = PXCache<TXSetup>.GetExtension<TXSetupExt>(txsetup);
Then you can access the extension fields like so:
var foo = rowExt.Usrfield;

Active Admin create additional URL on unique field

I have an object Foo which has fields id and token (both are unique, both have db indexes). I want to be able to get to Foo 1 by going to url "/admin/foos/token-of-foo-1" in addition to being able to use the url "/admin/foos/1". I know that I will need to do something like the below in my routes.rb, but I'm having trouble. Help?
ActiveAdmin.routes(self) # keep this
get 'admin/???', to: 'admin/???' # add ...something
Hmm, some thoughts:
#admin/foo.rb
controller do
def find_resource
if params[:id].length == 16 # it's a token
end_of_association_chain.find_by_token(params[:id])
else
end_of_association_chain.find(params[:id])
end
end
end
For this kind of purposes I use this gem called FriendlyID. You can select which fields should form the URL slug, in your case the field token:
class Foo < ApplicationRecord
extend FriendlyId
friendly_id :token, use: :slugged
end
Let me know if you have more doubts on how to configure. It has a great integration with Active Admin.

SQL Azure Database / Can't Insert Record into a Table / ID not getting set during SubmitChanges

In the following instance, I have tried to simplify an issue to root components.
I've got a very simple SQL Azure database where I created a test table called Table1. Azure creates an ID field with Is Required, Is Primary Key checked. It will NOT allow to check the box Is Identity. There are a couple of other fields which are simply required.
In my VS2012 Project, I have created an LinqToSql Class which created a ProductionDataClasses1.dbml object.
I simply want to add a record to this table thru the method shown below. From what I am reading, ID would be set during the SubmitChanges() after InsertOnSubmit(NewRecord) is specified.
It does work the first time but value is set to zero. On subsequent save, I get an exception (basically it a duplicate record because ID=0 already exists).
To put this into context, I have included some sample code below. The idea is to first check if the record exists and update. If not, I want to add a record.
My question is... Do I need to manually set ID? If so, how do I set the value to an int and how to a retrieve the next value. I tried changing to a Guid but not allowed.
Here is my code sample:
public bool AddTestRecord(string someValue)
{
ProductionDataClasses1DataContext context = new ProductionDataClasses1DataContext();
try
{
var ExistingRecord = context.Table1s.SingleOrDefault(c => c.TextKey == someValue);
if (ExistingRecord == null)
{
var NewRecord = new Table1();
// NewRecord.ID = ???? ; How Do I Manually Set. It is getting set to 0 causing a duplicate value exception
NewRecord.TextKey = someValue;
NewRecord.AnotherValue = DateTime.Now.ToShortTimeString();
context.Table1s.InsertOnSubmit(NewRecord);
}
else
{
ExistingRecord.AnotherValue = DateTime.Now.TimeOfDay.ToString();
}
context.SubmitChanges();
return true;
}
catch (Exception e)
{
Console.WriteLine(e.Message);
return false;
context.SubmitChanges();
}
}
I would suggest manually running a SQL script to alter the table and make the column an identity. Look at this answer
Adding an identity to an existing column
Thanks for your reply.
I just was finally able to make this work on a new table and will try to follow along your instructions to make modifications to my real table. My code (as written above) was OK so the issue is in the SQL Azure table definition.
I found the issue is that when you create a new table in SQL Azure, it creates a table with three fields, ID, Column1, Column2. By default, ID is set as the Primary Key but none are checked as Is Identity.
To make this work, I made ID the Is Identity and unchecked PrimaryKey and Column1 the In Primary Key. Thus when a new record is saved, the ID is set and Column1 is checked to make sure it is not already in the system. I had to do this when the table was first created. Once saved, it would not allow me to change.
Afterwards, I updated my Linq To SQL class and dropped the new table in. I noted that now the AutoGenerated Value on ID and PrimaryKey on Column1 was set and my code worked.

Magento observer (sales_order_grid_collection_load_before), filter collection by a product attribute

So I'm working with sales_order_grid_collection_load_before observer event at the moment, where I can get the collection being used through $collection = $observer->getEvent()->getOrderGridCollection();, I'm just wondering, if it is possible to filter this collection by a product from the order attribute.
What I mean with that is the order grid collection has sub products related to that order, I need to only show orders if at least one of the products match a specific criteria (in my case, I've given the products an admin_id attribute, which is set to the administrator who added the product).
Thanks!
I've done a very similar thing by doing the following:
Override the sales order grid block. To do this you will need to set up your own extension (it looks like you might already be doing this, but just in case, there is some handy doco in the Magento wiki)
<config>
<modules>
<Company_Module>
<version>0.1.0</version>
</Company_Module>
</modules>
<global>
<blocks>
<company_module>
<class>Company_Module_Block</class>
</company_module>
<adminhtml>
<rewrite>
<sales_order_grid>Company_Module_Block_Sales_Order_Grid</sales_order_grid>
</rewrite>
</adminhtml>
</blocks>
</global>
</config>
I then copied the /app/code/core/Mage/Adminhtml/Block/Sales/Order/Grid.php into my extensions folder at /app/code/local/Company/Module/Block/Sales/Order
In the copied file I changed the class name to class Company_Module_Block_Sales_Order_Grid extends Mage_Adminhtml_Block_Widget_Grid
I then changed the _prepareCollection function. In this case I was interested in grabbing the customer_group_id and customer_email from the sales_flat_order table
protected function _prepareCollection() {
$collection = Mage::getResourceModel($this->_getCollectionClass());
// left join onto the sales_flat_order table, retrieving the customer_group_id and customer_email columns -< this can be expanded
$collection->getSelect()->join('sales_flat_order', 'main_table.entity_id=sales_flat_order.entity_id', array('customer_group_id'=>'customer_group_id', 'customer_email'=>'customer_email'), null, 'left');
// grab the current user and get their associated customer groups (additional coding required to associate the customer groups to an admin user
$user = Mage::getSingleton('admin/session')->getUser();
$roleId = implode('', $user->getRoles());
$customerGroupIds = Mage::getModel('admin/roles')->load($roleId)->getCustomerGroupIds();
$orders = Mage::getResourceModel('sales/order_collection');
// if the admin user has associated customer group ids then find the orders associated with those
// this would be where you would do your filtering of the products
if (count($customerGroupIds)) {
$orders->addAttributeToFilter('customer_group_id', array('in' => $customerGroupIds));
}
$orderIds = $orders->getAllIds();
$collection->addAttributeToFilter('entity_id', array('in' => $orderIds));
$this->setCollection($collection);
return parent::_prepareCollection();
}
You may not need the join to the sales_flat_order table...you might be able to do it just by doing the filtering in the second part of the _prepareCollection function shown above. In my case, I was displaying the customer_group_id and the customer_email in the grid so that the user could manually filter, if required.
I am not sure if you can access directly the product from the order_grid_collection (I don't think so) but you can join this collection with sales_flat_order_item and then filter as you wish.
HTH

Query Trac for all tickets related to a user

How do I query for all trac tickets related to a user. i.e. all tickets for which the tickets were once assigned, assigned now, created , etc etc
Create custom queries to the ticket_change table. Some SQL required. For assigned once/now, look for rows where field='owner', newvalue column contains the user name the ticket was assigned to. For created tickets, just query by reporter in the ticket table.
Example:
SELECT p.value AS __color__,
id AS ticket, summary, component, version, milestone,
t.type AS type, priority, t.time AS created,
changetime AS _changetime, description AS _description,
reporter AS _reporter
FROM ticket t, enum p, ticket_change c
WHERE p.name = t.priority AND p.type = 'priority'
AND c.field = 'owner'
AND c.newvalue = '$USER'
AND c.ticket = t.id
ORDER BY p.value, milestone, t.type, t.time
You can express this with a TraqQuery expression. E.g. if you want the columns id, summary and status to show up and query all the tickets for the currently logged in user ($USER) then use the following query.
query:?col=id
&
col=summary
&
col=status
&
owner=$USER
However this query assumes that the owner hasn't been the same during the lifetime of a ticket (since ownership can be changed).
If you want a specific user then replace $USER with the actual username. Also if you're using the Agilo plugin you can easily create new queries on the fly via the web-UI. This is done by looking at a report and adding filters to the report.

Resources