POSLib.gtl 0 0
    include "DDS\PointOfSale.def"
    include "DDS\Order_Head.def"
    include "DDS\Invoice_Total.def"
    include "DDS\Invoice_Line.def"
    include "dds\CurrencyRate.def"
    
    let psDDS = DDS("PointOfSale") in
    let ohDDS = DDS("Order_Head") in
    let itDDS = DDS("Invoice_Total") in
    let ilDDS = DDS("Invoice_Line") in
    let cuDDS = DDS("CurrencyRate") in
    
    let Currency = "" in
    let pt, fWantGroup = NewRow ptDDS, 0 in
    let DeliverySalesExec = 0 in
    
    let GetPosHead(K) = valof
    {   let psFind = find(psDDS 0, K) in
        res psFind 1 = 0 -> NewRow(psDDS) | row(psDDS, psFind 1)
    } in
    
    let GetOrderHead(K) = valof
    {   let ohKey = find(ohDDS 0, K) in
        res ohKey 1 <> 0 -> row(ohDDS, ohKey 1) | NewRow(ohDDS)
    } in
    
    let GetInvoiceLine K = valof
    {   let ilFirst = find(ilDDS 0, K) in
        res (ilFirst 1 = 0) -> NewRow(ilDDS) | row(ilDDS, ilFirst 1)
    } in
    
    let GetInvoiceTotal(K) = valof
    {   let itKey = find(itDDS 0, K) in
        res (itKey 1) <> 0 -> row(itDDS, itKey 1) | NewRow(itDDS)
    } in
    
    let FindPosLine(le, d) = valof
    {   let ret = NewRow(leDDS) in
        let fContinue = 1 in
        while fContinue do
        {   let l = nextrow(leDDS, d) in
            if le _LERef = l _LERef & le _LELine = l _LELine do
            {   if l _LELedger = "TRADING     " & l _LEMain = "SALES       " do
                {   ret := l;
                    fContinue := 0
                } 
            } else fContinue := 0
        };
        res ret
    } in
    
    let FindPosHead(le) = valof
    {   res GetPosHead("POINTOFSALE ".(le _LERef!(0, 12))) 
    } in
    
    let MapPOSToInvoiceLine(le, d) = valof
    {   let il = NewRow(ilDDS) in
        let l = FindPosLine(le, d) in
        let gm = Retrieve(gmDDS, pt _PMGroup) in
        let gma = $Retrieved in
        il _ILTaxable := gma=0 -> 1| gm _PGTaxable;
        il _ILInvoiceNo := le _LERef;
        il _ILLine := le _LELine;
        il _ILProductCode := ((le _LEMain!(0, 12)).(le _LESub!(0, 12)))!(0, 16);
        il _ILItemsShipped := -le _LEItems;
        il _ILQuantity := -le _LEQuantity;
        il _ILTaxAmount := il _ILTaxable -> rc(-l _LEValue * cd _GSTRate / 100.0)| 0.0;
        il _ILExtension := rc(-l _LEValue + il _ILTaxAmount);
        res il
    } in
    
    \ returns a tuple of fMatch, dm, na, DeliveryKey
    \ fTrue indicates that the parameters are matched and that dm, na are valid
    let LookupInvoiceEx(le, d, fDebtorOnly) = valof
    {   let fMatch, dm, na, DeliveryKey = 0, (), (), "" in
        if le _LEType = "46" do
        {   let po = FindPosHead le in
            unless fDebtorOnly & blank(po _PSDebtor) do
            {   if blank (po _PSDebtor) do po _PSDebtor := "POINTOFSALE ";
                if up _URFromCustomer <= po _PSDebtor & po _PSDebtor <= up _URToCustomer do
                {   let oh = GetOrderHead("POINTOFSALE ".(le _LERef!(0, 12))) in
                    na := NameAddress(po _PSDebtor); 
                    dm := GetDebtor(po _PSDebtor);
                    dm _DMSalesExec := oh _OHSalesExec!(0, 12);
                    DeliveryKey := oh _OHDeliveryKey!(0, 12);
                    fMatch := 1
                }
            }
        } else
        {   let it = GetInvoiceTotal(le _LERef) in
            if up _URFromCustomer <= it _ITCustomer & it _ITCustomer <= up _URToCustomer do
            {   na := NameAddress(it _ITCustomer); 
                dm := GetDebtor(it _ITCustomer);
                dm _DMSalesExec := it _ITSalesExec!(0, 12);
                DeliveryKey := it _ITDelivery!(0, 12);
                if DeliverySalesExec do
                {   let da = NameAddress DeliveryKey in
                    dm _DMSalesExec := da _NASalesExec!(0, 12)
                };
                Currency := it _ITCurrency;
                fMatch := 1
            }
        };
        res (fMatch & WantSalesExec dm & WantDebtorCategory dm & WantTurnover dm & WantTerritory dm & WantPostCode na, dm, na, DeliveryKey)
    } in
    
    
    \ returns a tuple of fMatch, dm, na
    \ fTrue indicates that the parameters are matched and that dm, na are valid
    let LookupInvoice(le, d, fDebtorOnly) = valof
    {   let fMatch, dm, na, DeliveryKey = LookupInvoiceEx(le, d, fDebtorOnly) in
        res fMatch, dm, na
    } in
    
    let LookupInvoiceLine(le, d) = valof
    {   if le _LEType = "46" do res MapPOSToInvoiceLine(le, $d) else
        if blank(le _LELine) do                                             \Just for missing LELine data
        {   let il = NewRow ilDDS in
            let Map(k, d) =
            {   let il0 = row(ilDDS, d) in
                if il0 _ILProductCode = (le _LEMain.le _LESub)!(0, 16) do
                {   il := il0;
                    endmap()
                }
            } in
            map(ilDDS 0, le _LERef."      ", le _LERef."zzzzzz", Map);
            res il
        } else res GetInvoiceLine(le _LERef.le _LELine)
    } in
    
    let fPricesExGST, GSTRate  = 0, 0.0 in
    let NoForex = 0 in
    
    \ returns Items, Qty, Gross, Tax, Nett, Cost, GP
    \ Tax includes GST and WET
    let CalculateNett(le, d) = valof
    {   let il = LookupInvoiceLine(le, d) in
        let Items, Qty, Gross, Tax, Nett, Cost, GP = 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 in
    \   if le _LERef = "NS260653" do SpawnWarn("CalculateNett", ShowRecord(leDDS, le), ShowRecord(ilDDS, il));
        fPricesExGST := cd _PricesExcludeGST = "Y" or cd _SellPricesExcludeGST = "Y";
        if le _LEType = "46" do fPricesExGST := 0;                                      \POS always has GST
        if fPricesExGST do GSTRate := cd _GSTRate / 100.0 else
                           GSTRate := cd _GSTRate / (100.0 + cd _GSTRate);
        if #le _LELedger = "TRADING" & #le _LEMain = "SALES" & #le _LESub = "NON STOCK" do res le _LEItems, le _LEQuantity, -le _LEValue, 0.0, -le _LEValue, 0.0, -le _LEValue;
        Cost := le _LEValue;
        Qty := il _ILQuantity;
        Items := il _ILItemsShipped;
    
        if islambda(lookup("GetEmployeeCost")) do Cost += GetEmployeeCost(le, $d);
    
    \   il _ILExtension := rc(il _ILExtension);
    \   if le _LEType = "46" do { il _ILExtension:(10, 6); nl() };
    
        if Feature "LIQUOR RETAIL" do
        {   Gross := il _ILExtension;
            Nett  := il _ILExtension;
            GP    := Nett + Cost
        } else
        if fPricesExGST do
        {   if il _ILTaxable do Tax := il _ILExtension * GSTRate;
            Gross := il _ILExtension + Tax;
            Nett  := il _ILExtension;               \ Don't include WineTax in Nett Amount
            GP    := Nett + Cost
        } else
        {   \NOTE: WineTax is not support in Prices Inc GST 
            if il _ILTaxable do Tax := il _ILExtension * GSTRate else Tax := 0.0;
            Gross := il _ILExtension;
            Nett  := Gross - Tax;
            GP := Nett + Cost
        };
        unless NoForex or blank Currency do
        {   let cu = Retrieve(cuDDS, Currency) in
            let R = cu _CUSellRate in
            if sig(2, R) do
            {   Gross := Gross / R;
                Nett := Nett / R;
                Tax := Tax / R;
                GP := Nett + Cost
            }
        };
        res Items, Qty, Gross, Tax, Nett, Cost, GP
    } in
    
    let IsSalesType T = valof
    {   res T = "15" -> TRUE |
            T = "46" -> TRUE |
            T = "30" -> TRUE |
            T = "14" -> TRUE | FALSE
    } in
    
    let m = 0 in
    
    let Sort t = valof
    {   clear(); absco(300, 300); "Sorting..."; NL; 
        res sort t
    } in
    
    let Rank() = 
    {   clear(); absco(300, 300); "Ranking..."; NL
    } in
    
    let ProductCache K = valof
    {   unless K = pt _ProductCode do
        {   pt := GetProduct K;
            if blank(pt _ProductCode) do pt _ProductCode := K!(0, 16);
            fWantGroup := WantGroup(pt _PMGroup)
        };
        res $pt
    } in
    
    let LookupAndWantGroup le = valof
    {   let pt = ProductCache((le _LEMain.le _LESub)!(0, 16)) in
        res fWantGroup
    } in
    
    let MatchCommonSalesParameters(le, fIncType14) = valof
    {   let m =
        IsSalesType(le _LEType) &
        up _URFromPeriod <= le _LEPeriod & le _LEPeriod <= up _URToPeriod &
        up _URFromDate <= le _LEDate & le _LEDate <= up _URToDate & LookupAndWantGroup le in
    \   if le _LERef = "NS260653" do SpawnWarn("MatchCommonSalesParameters", m, le _LERef, ShowRecord(leDDS, le));
        res m
    } in
    define SALES_PACKAGE 0x1F6
    let DefineCommonSalesParameters() = 
    {   Package := Package || SALES_PACKAGE;
        pPeriods, pDates, pProducts, pGroups := 1, 1, 1, 1;
        pCustomers, pSalesExecs, pCategories, pTurnover, pTerritory, pPostCodes := 1, 1, 1, 1, 1, 1
    } in
    
    let GenerateMonthHeadings t = valof
    {   let fp = Period(up _URFromPeriod) in
        let m = (
                "    ".ShowPeriod(fp),
                "    ".ShowPeriod(fp+1),
                "    ".ShowPeriod(fp+2),
                "    ".ShowPeriod(fp+3),
                "    ".ShowPeriod(fp+4),
                "    ".ShowPeriod(fp+5),
                "    ".ShowPeriod(fp+6),
                "    ".ShowPeriod(fp+7),
                "    ".ShowPeriod(fp+8),
                "    ".ShowPeriod(fp+9),
                "    ".ShowPeriod(fp+10),
                "    ".ShowPeriod(fp+11), 
                "    Year To") in
        if istuple t do res Conc(t, m) else res Conc(() aug t, m)
    } in
    let GenerateNarrowMonthHeadings t = valof
    {   let fp = Period(up _URFromPeriod) in
        let m = (
                ShowPeriod(fp)." ",
                ShowPeriod(fp+1)." ",
                ShowPeriod(fp+2)." ",
                ShowPeriod(fp+3)." ",
                ShowPeriod(fp+4)." ",
                ShowPeriod(fp+5)." ",
                ShowPeriod(fp+6)." ",
                ShowPeriod(fp+7)." ",
                ShowPeriod(fp+8)." ",
                ShowPeriod(fp+9)." ",
                ShowPeriod(fp+10)." ",
                ShowPeriod(fp+11)." ", 
                "   YTD ") in
        if istuple t do res Conc(t, m) else res Conc(() aug t, m)
    } in