how to update a non updatable view? - python-3.x

I'm working on odoo version11. I created a view named test. I upgraded the module. Later I need to make some changes including changing some values and removing some values. Whenever I try to upgrade the module I get the error
psycopg2.OperationalError: cannot delete from view "test" DETAIL:
Views containing GROUP BY are not automatically updatable. HINT: To
enable deleting from the view, provide an INSTEAD OF DELETE trigger or
an unconditional ON DELETE DO INSTEAD rule.
How to provide the rule? My code is as follows
#api.model_cr
def init(self):
cr = self.env.cr
tools.drop_view_if_exists(cr, 'o_test')
cr.execute("""
CREATE or replace view o_test as
(
SELECT
mve.id as id,
acc.code as account_code,
SUM (mve.debit-mve.credit) AS balance,
mve.account_id as account_id
FROM account_move_line mve
LEFT JOIN account_account acc ON mve.account_id = acc.id
GROUP BY mve.id,mve.account_id,acc.code
)
""")
I want to change the code to as follows:
#api.model_cr
def init(self):
cr = self.env.cr
tools.drop_view_if_exists(cr, 'o_test')
cr.execute("""
CREATE or replace view o_test as
(
SELECT
mve.account_id as id,
acc.code as account_code,
SUM (mve.debit-mve.credit) AS balance,
mve.account_id as account_id
FROM account_move_line mve
LEFT JOIN account_account acc ON mve.account_id = acc.id
GROUP BY mve.account_id,acc.code
)
""")

Editable Views can be created in Postgres using Rules and GROUP BY clause should not be a problem. You can write rule like the below for update query. Here I have updated only one column
CREATE OR REPLACE RULE update_o_test AS
ON UPDATE TO o_test
DO INSTEAD
UPDATE account_account SET code = new.code
WHERE account_account.id = old.id;
Similarly you can create rules for Insert and Delete operations. Adding rules after the end of your create view statement should work.
Hope this helps...

Related

NetSuite Search formula for items that have no open transactions

I am trying to create a formula to obtain a list of items that have no open transactions.
I cant just filter out by status as this filters out transactions that are open, as opposed to showing me only items with nothing open.
So basically if an item has anything open then i dont want it on the search. I do need it on the search if it has all closed or it has no transactions at all.
Hoping someone can help put me in the right direction.
I am a little bit stuck at where to start with the formulas and tried a case formula.
You can use item saved search adding under criteria as "Transaction Fields-status-anyOf-select all closed/rejected/declined statuses" not in filter reason of saved search.
Thanks.
To get the value of non transaction items as well, You need to check the check box use expression under criteria in standard subtab use parens() with OR expression.
And add one more condition as "Transaction Fields-Internal Id-anyOf-none with
"Transaction Fields-status-anyOf-select all closed/rejected/declined statuses".
Add both condition with OR logic.
It will work for both items condition if it has transaction status with closed or with none of transaction internal ids.
Thanks.
I think this is possible in a saved search, and requires a change in the way the filtering is done. Rather than filtering on the "Filters", using grouping and summary calculations to determine if an item qualifies, basically :
Create the item saved search as you would normally, but don't include a "Standard" filter for the openness of the transaction.
In the results, group by item name (or internalid), and another fields you want to include in the top-level results.
In the Criteria - Summary list, add a Formula (Number) condition :
Summary Type= Sum (Count won't work here)
Formula = case when {transaction.status} = 'Open' then 1 else 0 end
Equal to 0
Whether this is more or less elegant than bknight's answer is debatable.
I don't think this is the sort of thing you can do with a single saved search.
It would be fairly easy to do with SuiteQL though.
The script below runs in the console and finds items that are not on any Pending Billing Sales Orders. It's adapted from a script with a different purpose but illustrates the concept.
You can get a list of the status values to use by creating a saved search that finds all the transactions with open statuses you want to exclude , take note of that saved search's id and running the second script in the console
require(['N/query'], query => {
const sqlStr = `
select item.id, itemid, count(po.tranid) as po, count(bill.tranId) as bill, max(bill.tranDate) as lastBilled, count(sale.tranId) as sales, count(tran.tranId) as trans
from item
left outer join transactionLine as line
on line.item = item.id
left outer join transaction as tran on line.transaction = tran.id
left outer join transaction as po on line.transaction = po.id and po.type = 'PurchOrd'
left outer join transaction as bill on line.transaction = bill.id and bill.type = 'VendBill'
left outer join transaction as sale on line.transaction = sale.id and sale.type in ('CustInvc', 'CashSale')
where item.id not in (select otl.item from transactionLine otl, transaction ot where
otl.transaction = ot.id and ot.status in ('SalesOrd:F'))
group by item.id, item.itemid
`;
console.log(sqlStr);
console.log(query.runSuiteQL({
query: sqlStr
}).asMappedResults().map((r, idx)=>{
if(!idx) console.log(JSON.stringify(r));
return `${r.id}\t${r.itemid}\t${r.po}\t${r.bill}\t${r.lastBilled}\t${r.sales}\t${r.trans}`;
}).join('\n'));
});
require(['N/search'], search=>{
const filters = search.load({id:304}).filters;
console.log(JSON.stringify(filters.find(f=>f.name == 'status'), null, ' '));
});
In terms of doing something with this you could run this in a saved search and email someone the results, show the results in a workbook in SuiteAnalytics or build a portlet to display the results - for this last Tim Dietrich has a nice write up on portlets and SuiteQL

typeORM Postgres how to add to left join function an "and where" condition from another table column?

I'm coding a big query to retrieve information about orders. Now I'm trying to left join a table (It works fine) but to enhance the query I would like to add on-where condition to the left-join function. Is it possible?
let containerBuilder = getManager()
.createQueryBuilder(Container, 'container')
.leftJoinAndSelect('container.surrenderDetails', 'surrenderDetails')
.leftJoinAndSelect('surrenderDetails.shipper', 'shipper')
.leftJoinAndSelect('shipper.shipperRenditionAddress', 'shipperRenditionAddress')
.leftJoinAndSelect('shipperRenditionAddress.node', 'node')
.orderBy('containersHistory.id', 'DESC');
This queryBuilder works fine but I would like to add a where condition inside the leftJoinAndSelect function, I coded the same query in pgAdmin 4 to retrieve the specific information I want but I'm not sure if I can reply the same logic with typeOrm. Do you have any idea? Thanks!
SELECT "con"."id", "con"."containerType", "con"."trackingId", "con"."originNode",
"sra"."address", "sra"."zipCode", "sra"."province"
FROM "container" con
LEFT JOIN "surrender_details" sud
ON ("con"."id" = "sud"."Container")
LEFT JOIN "shipper_rendition_address" sra
ON ("sud"."shipper" = "sra"."shipperId" AND "con"."originNode" = "sra"."nodeId")
Basically I want to add this line "AND "con"."originNode" = "sra"."nodeId" to retrieve only the rows that matched with the container node. I try to code the next line but I recived a error code
.leftJoinAndSelect('shipperRenditionAddress.node', 'node', 'node = :nodeId, {'nodeId': 'container.node')

SQL trigger with parameter

I have a nodejs app with SQL Server. I want to be able to update a table for a "specific org" based on an insert and delete action. Let's say I have 2 tables as follows:
Project: projId, orgId, projName
Tasks: taskId, projId, taskName
Users: userId, orgId, userName
OrganizationStats: numberOfProjects, numberOfUsers, numberOfTasks orgId
So let's say I add a new project for an organization where orgId = 1. My insert statement from Nodejs would be:
insert into project (projId, orgId, projName)
values (${'projId'}, ${'orgId'}, 'New Project');
I want to write a trigger in SQL Server that adds 1 to the numberOfProjects column with orgId that's passed in.
create trigger updateProjectAfterInsert
on project
after insert
as
begin
update OrganizationStats
set numprojects = numberOfProjects + 1
where orgId = 'THE_INSERTED_ORGID_VALUE';
end;
My problem is I don't know how to pass the ${'orgId'} to the trigger.
I'm going to expand on my comment here:
Personally, I recommend against storing values which can be calculated by an aggregate. If you need such information easily accessible, you're better off making a VIEW with the value in there, in my opinion.
What I mean by this is that NumProjects has "no right" being in the table OrganizationStats, instead it should be calculated at the time the information is needed. You can't use an aggregate function in a computed column's definition without a scalar function, and those can be quite slow. Instead I recommend creating a VIEW (or if you prefer table value function) to give you the information from the table:
CREATE VIEW dbo.vw_OrganisationStats AS
SELECT {Columns from OrganizationStats},
P.Projects AS NumProjects
FROM dbo.OrganizationStats OS
CROSS APPLY (SELECT COUNT(*) AS Projects
FROM dbo.Projects P
WHERE P.OrgID = OS.OrgID) P;
I use a CROSS APPLY with a subquery, as then you don't need a huge GROUP BY at the end.
I think what you want this something like this:
CREATE TRIGGER updateProjectAfterInsert
ON Project
AFTER INSERT
AS
BEGIN
UPDATE OrganizationStats
SET NumProjects = NumProjects + 1
WHERE OrgId IN (SELECT OrgId FROM inserted);
END;
Also note, Triggers must always assume multiple rows. It's possible to insert multiple rows, update multiple rows, and delete multiple rows. The "inserted" and "deleted" collections contain the data needed ("inserted" contains the rows being inserted, "deleted" contains the rows being deleted, and on an update "inserted" contains the values after the update, and "deleted" contains the values before the update).

Populating custom table on Shipment release

I have created a custom table and made it available on the Customers screen called 'Serial Tracking'. The purpose of this screen is to track serialised items that each customer is in possession of (regardless of who the item was purchased from).
I would like a record automatically added to the table on shipment release. I have attempted to customise the Release method of SoShipmentEntry but am having trouble getting all the required data together as well as the best way to structure the code.
The custom table DAC is
AUSerialTrack
Not necessarily the answer to your question but to long for a comment.
As an alternative, what if you set your Serials tab view to the Ship Line Split table without dealing with a custom table. You could get the information you needed with something like this: (need to convert to your BQL view for your serials tab)
SELECT [ship].[CustomerID],
[ship].[ShipmentNbr],
[split].[InventoryID],
[split].[LotSerialNbr]
FROM [dbo].[SOShipLineSplit] split
INNER JOIN [dbo].[SOShipLine] line
ON [line].[CompanyID] = [split].[CompanyID]
AND [line].[ShipmentNbr] = [split].[ShipmentNbr]
AND [line].[LineNbr] = [split].[LineNbr]
INNER JOIN [dbo].[SOShipment] ship
ON [ship].[CompanyID] = [split].[CompanyID]
AND [ship].[ShipmentNbr] = [split].[ShipmentNbr]
INNER JOIN [dbo].[InventoryItem] i
ON [i].[CompanyID] = [split].[CompanyID]
AND [i].[InventoryID] = [split].[InventoryID]
INNER JOIN [dbo].[INLotSerClass] c
ON [c].[CompanyID] = [i].[CompanyID]
AND [c].[LotSerClassID] = [i].[LotSerClassID]
WHERE [c].[LotSerTrack] = 'S'
AND [ship].[Confirmed] = 1;
Then when the user goes to the tab its always the current results. No custom code to fill in a custom table so easier for upgrades/customization maintenance.

Writing a subquery to display records in a grid

I have two DAC's POReceipt, and and POReceiptLine. POReceiptLine containts a field called MfrPartNbr.
I want the user to be able to lookup all the POReceipts where the POReceiptLine.MfrPartNbr is equal to an entered value.
The SQL would be
SELECT *
FROM dbo.POReceipt
WHERE POReceipt.ReceiptNbr IN
(
SELECT ReceiptNbr
FROM dbo.POReceiptLine
WHERE MfrPartNbr = 'MY_ENTERED_PART_NBR'
)
Any idea how to write the BQL Statement for this?
As stated, an inner join won't work in this case because you will receive the same POReceipt multiple times (once for each POReceiptLine). The following BQL query shows how you can get the desired results using a sub query. If mfrPartNbr is an extension field, then replace POReceiptLine.mfrPartNbr with the correct extension name (e.g. POReceiptLineExtension.mfrPartNbr).
PXSelect<POReceipt, Where<Exists<
Select<POReceiptLine,
Where<POReceiptLine.receiptNbr, Equal<POReceipt.receiptNbr>,
And<POReceiptLine.mfrPartNbr, Equal<Required<POReceiptLine.mfrPartNbr>>>>>>>>.Select(this, "MY_ENTERED_PART_NBR");

Resources