Assign a value from Gen Business Posting Group Table - microsoft-dynamics

I have got Gen Bus. Posting Group field showing on the subform of Sales Order. This Subform is also showing Location Code for the Line.
I am attempting to write a logic as such that if the User selects Location Code as DROPSHIP, the Gen Bus. Posting Group should be LOCAL-DROPSHIP.
LOCAL-DROPSHIP is a record in the Gen. Bus. Posting Group. I have created it before writing this code. However, it would not assign to my rec.Gen Bus. Posting Group.
Here is the code on the Subform;
modify("Location Code")
{
trigger OnAfterValidate()
var
recLocation: Record Location;
recCustomer: Record Customer;
recSalesLine: Record "Sales Line";
recGenPosting: Record "Gen. Business Posting Group";
begin
recGenPosting.Get('LOCAL-DS');
if rec."Location Code" = 'DROPSHIP' then begin
Message(recGenPosting.Code);
// Validate("Gen. Bus. Posting Group", recGenPosting.Code);
Rec."Gen. Bus. Posting Group" := recGenPosting.Code;
CurrPage.Update();
end;
end;
}

You should do this as Table Extension of Table Sales Line instead of Page Extension. Validate is important in this case.

Extended Sales Line table, on the OnModify trigger, wrote;
if rec."Location Code" = 'DROPSHIP' then begin
If recCustomer.Get(REC."Sell-to Customer No.") THEN begin
if recCustomer."Country/Region Code" = 'CITY' then begin
rec."Gen. Bus. Posting Group" := 'DS';
rec.Modify();
end
end

Related

Bigquery, how to count events group by week?

I just started working with Bigquery. Data comes from firebase and I noticed that I got the data each day, for example gara-e78a5.analytics_247657392.events_20221231, gara-e78a5.analytics_247657392.events_20221230 etc....
Each row comes with an event_date like under this format 20221231
I want to count the number of people landing on our page each week, but I don't know I to group them by week.
I started something like this but I don't know to group it by week:
SELECT count(event_name) FROM app-xxxx.analytics_247657392.events_* where event_name = 'page_download_view' group by
Thanks in advance for your help
Based on #Ronak, i found the solution.
SELECT week_of_year, sum(nb_download) as nb_download_per_week from (
SELECT DISTINCT EXTRACT (WEEK from (PARSE_DATE('%Y%m%d', event_date))) as week_of_year, count(event_name) as nb_download from `tabllle-e78a5.analytics_XXXXX.events_*` where event_name = 'landing_event_download_apk' group by event_date) group by week_of_year
You can use the WEEK (or ISOWEEK) function.
WEEK: Returns the week number of the date in the range [0, 53]
More: https://cloud.google.com/bigquery/docs/reference/standard-sql/date_functions
Formats - https://cloud.google.com/bigquery/docs/reference/standard-sql/timestamp_functions#format_timestamp
This should work
select EXTRACT(ISOWEEK FROM(CAST(PARSE_DATE('%Y%m%d', <column>) as TIMESTAMP))) as week_of_year from <table>
Output

Replace Traffic Source from raw Google analytics session data in Bigquery?

Recently we observed that when a user tries to complete a transaction on our website using an ios device. Apple ends the current session and begins a new session. The difficulty with this is that if the user came through paid source/email the current session ends and starts a new session with apple.com traffic source.
For Instance
google->appleid.apple.com
(direct)->appleid.apple.com
email->appleid.apple.com
ios->appleid.apple.com->appleid.apple.com->appleid.apple.com
Since we have this raw data coming into BQ we are looking at replacing appleid.apple.com with their actual traffic Source i.e. google,direct,email,ios.
Any help regarding the logic/function to workaround this problem will help?
This is the code I tried implementing:
WITH DATA AS (
SELECT
PARSE_DATE("%Y%m%d",date) AS Date,
clientId as ClientId,
fullVisitorId AS fullvisitorid,
visitNumber AS visitnumber,
trafficSource.medium as medium,
CONCAT(fullvisitorid,"-",CAST(visitStartTime AS STRING)) AS Session_ID,
trafficsource.source AS Traffic_Source,
MAX((CASE WHEN (hits.eventInfo.eventLabel="complete") THEN 1 ELSE 0 END)) AS ConversionComplete
FROM `project.dataset.ga_sessions_20*`
,UNNEST(hits) AS hits
WHERE totals.visits=1
GROUP BY
1,2,3,4,5,6,7
),
Source_Replace AS (
SELECT
Date AS Date,
IF(Traffic_Source LIKE "%apple.com" ,(CASE WHEN Traffic_Source NOT LIKE "%apple.com%" THEN LAG(Traffic_Source,1) OVER (PARTITION BY ClientId ORDER BY visitnumber ASC)end), Traffic_Source) AS traffic_source_1,
medium AS Medium,
fullvisitorid AS User_ID,
Session_ID AS SessionID,
ConversionComplete AS ConversionComplete
FROM
DATA
)
SELECT
Date AS Date,
traffic_source_1 AS TrafficSource,
Medium AS TrafficMedium,
COUNT(DISTINCT User_ID) AS Users,
COUNT(DISTINCT SessionID) AS Sessions,
SUM(ConversionComplete) AS ConversionComplete
FROM
Source_Replace
GROUP BY
1,2,3
Thanks
Does assuming the visitStartTime as key to identifying the session start help? Maybe something like:
source_replaced as (
select *,
min(Traffic_Source) over (
partition by date, clientid, fullvisitorid, visitnumber order by visitStartTime
) as originating_source
from data
)
Then you can do your aggregation over the originating_source. Its kind of difficult without looking at some sample of data about whats going on.
Hope it helps.

Using RLS on secondary field to UserPrincipalName

So if I have three users: Tom, Dick, and Harry, and they have been assigned group colors. I'd like them to be able to see everyone's data in their own group.
Name Group Email
----- ----- -----
Tom Green t#acme.com
Dick Red d#acme.com
Harry Red h#acme.com
So I create a measure
RLS_SecurityKey = CALCULATE(FIRSTNONBLANK(People[Group],People[Group]),
USERPRINCIPALNAME() = People[Email])
And when I log in as the separate users, I can see in a card visual that I'm getting the expected group.
But when I set row level security on the People table, [Group] = [RLS_SecurityKey], I only get back the one row that matches the email address and not the user that matches his Group.
It seems I'm missing something fairly apparent, but I can't see it. How can I get back all the rows relating to Group and not the email?
Yep, it was pretty straight forward.
RLS_SecurityKey = CALCULATE(FIRSTNONBLANK(People[Group],People[Group]),
FILTER(ALL('PEOPLE'),USERPRINCIPALNAME() = People[Email]))
I adjusted the filter expression and made it a proper filter over the whole table.

How to add contacts to customer

I try to add contacts to a customer, like this:
WHILE (LoopCount <> 0) DO
BEGIN
KlantContact.GET(FirstContact);
KlantContact.VALIDATE(KlantContact."Company No.", BussinesContactName."Contact No."); //'44241';
KlantContact.MODIFY;
MESSAGE(KlantContact.Name);
LoopCount := LoopCount - 1;
FirstContact := INCSTR(FirstContact);
END;
But the problem is that the contacts are not connected with the customer.
You have to use the Contact Business Relation table to link them together. Just check the table structure.
Otherwise, if you set up the Bus. Relation Codes in the Marketing Setup NAV will create a new Contact in the background for Customers, Vendors and Bank Accounts.
If you look in the OnInsert trigger of the Customer Table you can see, that a Method UpdateContFromCust.OnInsert(Rec); is called. Within this Method a new Contact Bus. Relation is inserted.
From Method InsertNewContact (Codeunit 5056), with Cont beeing the contact and RMSetup beeing Marketing Setup
WITH ContBusRel DO BEGIN
INIT;
"Contact No." := Cont."No.";
"Business Relation Code" := RMSetup."Bus. Rel. Code for Customers";
"Link to Table" := "Link to Table"::Customer;
"No." := Cust."No.";
INSERT(TRUE);
END;

Dynamics NAV Sales Invoice Report: Modifying the SalesShipmentBuffer and findPostedShipmentDate()

I have recently modified the default report 207 Sales Invoice and created a custom report. One request I had, was to display Shipment information on this invoice for each shipment that the current invoice covers. Particularly I needed to show the following values:
Shipment No. from the Delivery Note
Quantity of the Shipment
The standard report only shows the posted shipment date and the quantity and that only for one shipment (I believe its the last one). It does not show the "Shipment No.".
When making the required changes I had several problems and it was difficult to find any information about the findPostedShipmentDate() function, so I have decided to post my solution here.
The question would be:
How can I show multiple shipments on the sales invoice?
How can I show the "Shipmente No." and the individual quantities or each shipment?
In the function "Sales Invoice Line"::OnAfterGetRecord() the function findPostedShipmentDate() is called. This function performs several checks to find the posting date and if necessary calls the function GenerateBufferFromValueEntry() which fills the table "SalesShipmentBuffer" which temporary stores all the shipment information for the current "Sales Invoice Line" record:
CASE "Sales Invoice Line".Type OF
"Sales Invoice Line".Type::Item:
GenerateBufferFromValueEntry("Sales Invoice Line");
...
Afterwards it performs several checks on the buffer table and deletes the entries again (more on this later).
In the GenerateBufferFromValueEntry the following happens. The actual shipment information is stored in the ItemLedgerEntry (32) table, in order to find the correct rows, the ValueEntry (5802) table is used, which contains the right key (ValueEntry."Item Ledger Entry No.").
Additionally to the existing range filters I needed to add one line to limit the range to the Item No. and I had to remove the range filter for the Entry No.. I also modified the function AddBufferEntry to additionally take the ItemLedgerEntry."Document No." which contains the Shipment No. from the delivery note. Here is the complete code:
TotalQuantity := SalesInvoiceLine2."Quantity (Base)";
ValueEntry.SETCURRENTKEY("Document No.");
ValueEntry.SETRANGE("Document No.",SalesInvoiceLine2."Document No.");
ValueEntry.SETRANGE("Posting Date","Sales Invoice Header"."Posting Date");
ValueEntry.SETRANGE(ValueEntry."Item No.", "Sales Invoice Line"."No."); //Added
ValueEntry.SETRANGE("Item Charge No.",'');
//ValueEntry.SETFILTER("Entry No.",'%1..',FirstValueEntryNo); //Removed
IF ValueEntry.FIND('-') THEN BEGIN
REPEAT
IF ItemLedgerEntry.GET(ValueEntry."Item Ledger Entry No.") THEN BEGIN
IF SalesInvoiceLine2."Qty. per Unit of Measure" <> 0 THEN
Quantity := ValueEntry."Invoiced Quantity" /
SalesInvoiceLine2."Qty. per Unit of Measure"
ELSE
Quantity := ValueEntry."Invoiced Quantity";
AddBufferEntry(
SalesInvoiceLine2,
-Quantity,
ItemLedgerEntry."Posting Date",
ItemLedgerEntry."Document No."); //Added
TotalQuantity := TotalQuantity + ValueEntry."Invoiced Quantity";
END;
FirstValueEntryNo := ValueEntry."Entry No." + 1;
UNTIL (ValueEntry.NEXT = 0) OR (TotalQuantity = 0);
END;
In the FindPostedShipmentDate function I also deleted the first couple of lines to prevent the function from exiting before the SalesShipmentBuffer had been filled:
IF "Sales Invoice Line"."Shipment No." <> '' THEN
IF SalesShipmentHeader.GET("Sales Invoice Line"."Shipment No.") THEN
EXIT(SalesShipmentHeader."Posting Date");
IF "Sales Invoice Header"."Order No."='' THEN
EXIT("Sales Invoice Header"."Posting Date");
In the last part of FindPostedShipmentDate the records of SalesShipmentBuffer are deleted again, which might seem a bit strange at first (it did to me). The reason is that even after the DELETE and DELETEALL functions are called, the record variable retains the values that were stored in the record before calling these functions. So the result is that the SalesShipmentBuffer tables is cleared, such that its empty for the next run of the findPostedShipmentDate() function, but the values can still be used in the report. The other confusing part is that actually does a very simple thing which is made to look very complicated. If the buffer contains only one line it deletes the line, otherwise if it contains more than one line it first calculates the sum of all quantity fields and then deletes all lines.
Anyway, I only had to make one change, which was removing the following line since the Document No. field now contains the Shipment No. and not the Invoice No.
SalesShipmentBuffer.SETRANGE("Document No.","Sales Invoice Line"."Document No.");
Here is the remaining code:
SalesShipmentBuffer.SETRANGE("Line No." ,"Sales Invoice Line"."Line No.");
SalesShipmentBuffer.SETRANGE("No." ,"Sales Invoice Line"."No.");
IF SalesShipmentBuffer.FIND('-') THEN BEGIN
SalesShipmentBuffer2 := SalesShipmentBuffer;
IF SalesShipmentBuffer.NEXT = 0 THEN BEGIN
SalesShipmentBuffer.GET(
SalesShipmentBuffer2."Document No.",
SalesShipmentBuffer2."Line No.",
SalesShipmentBuffer2."Entry No."
);
SalesShipmentBuffer.DELETE;
EXIT(SalesShipmentBuffer2."Posting Date");
END ;
SalesShipmentBuffer.CALCSUMS(Quantity);
IF SalesShipmentBuffer.Quantity <> "Sales Invoice Line".Quantity THEN BEGIN
SalesShipmentBuffer.DELETEALL;
EXIT("Sales Invoice Header"."Posting Date");
END;
END ELSE
EXIT("Sales Invoice Header"."Posting Date");
That's it. Now I just had to modify the DataItem source entries to show the necessary fields on the report.
The changes I had to make are actually not so many, but the code is not documented at all and I could not find much information when I googled for this problem or the functions involved. So I hope my post is helpful, in case someone has a similar problem than I had.
On a side not, I do not understand why the above code segment is written in such a wired why, I belive (though I have not verified this), that it could be simplified into the following code, which is much more readable. Please leave comments if you feel that my analysis is wrong.
SalesShipmentBuffer.SETRANGE("Line No." ,"Sales Invoice Line"."Line No.");
SalesShipmentBuffer.SETRANGE("No." ,"Sales Invoice Line"."No.");
SalesShipmentBuffer.FINDFIRST;
IF SalesShipmentBuffer.COUNT > 0 THEN BEGIN
IF SalesShipmentBuffer.COUNT = 1 THEN BEGIN
SalesShipmentBuffer.DELETE;
EXIT(SalesShipmentBuffer2."Posting Date");
END ELSE BEGIN
SalesShipmentBuffer.CALCSUMS(Quantity);
SalesShipmentBuffer.DELETEALL;
EXIT("Sales Invoice Header"."Posting Date");
END;
END ELSE
EXIT("Sales Invoice Header"."Posting Date");