Deliverycontrol
Service DeliveryControl
Synopsis
Service to control outgoing data.
Service Data structures
- Record TArticleDescriptor
- ArticleID (Integer) ID of Article to add.
- ArticleCode (String) code of Article to add.
- Quantity (Integer) Quantity of article to add.
- StockCode (integer) stock code to use when adding article.
- DutyCleared (boolean) duty cleared article or not ?
-
CustomPickJobID (int64) custom Locations from which to pick article. (0 if none)
-
TPickPackCounts
- PickedQtyDiff
- CheckedQtyDiff
- NotPickedCount
-
NotCheckedCount
-
Enumerated TScanResetOperation
- sroPick Reset pick data.
- sroCheck Reset check data.
-
sroBoth Reset both pick and check data.
-
Array TIDArray
-
array of int64 values.
-
Record TPickjobDescriptor
- InvoiceID (int64) Invoice ID
-
TrolleyLocationID (string?) Trolley location .
-
Record TPickScanDescriptor
- InvoiceID (int64)
- ArticleID (int64)
- StockCode (String)
- LocationID (Integer)
-
LotNo (string)
-
Record TPickCheckScanResult
- DisplayMessage (string)
- StartScanDate (DateTime)
-
HaveLotNo (Boolean)
-
Record TArticleScanDataDescriptor
- PickJobID (int64)
- ArticleID (int64)
- LocationID (int64)
- OutDetailID (int64)
- TransitLocation (string)
- SingleRow (Boolean)
-
StockCode (string)
-
Record: TSaveScanResult
- LocationEmptyStock : Boolean;
- PickJobDone Boolean;
Service Calls
UpdateOutgoingArticleCount
Service call to update counts on outgoing articles. (sample code : unit204, updaterow)
Declaration:
Procedure UpdateOutgoingArticleCount(aOrderID : int64; aArticle : String);
SELECT
ID, qty, QtyCF, CheckedQty, ID, PickedBy,
qty-isnull(CheckedQty, 0) as RESTQTY
from
Outdetails
WHERE
(avizno=:aOrderID)
AND (ARTCODE=:aArticle)
AND (qty>isnull(CheckedQty, 0))
ORDER BY
outdetails.ID asc
Article cannot be added, over-delivery ?);
UPDATE
OutOrderDetail
SET
odQuantityCurrent=isnull(odQuantityChecked, 0)+1,
odPickedByFK=:CurrentUser,
odPickedBy2FK=:CurrentUser,
odQuantityChangedOn=GetDate()
WHERE
(odID=:aID)
UPDATE
OutOrderDetail
SET
odQuantityChecked = isnull(odQuantityChecked, 0)+1,
odCheckedByFK=:currentuser,
odCheckedOn=GetDate()
WHERE
(odID=:aID)
UPDATE OUTDETAILS SET
checkedqty=isnull(CheckedQty, 0)+1
WHERE
(ID=:AID)
CreateNewColli
Call to allocate a new colli number:
Declaration:
Function CreateNewColli(aOrderID : int64) : Integer;
INSERT INTO OutdetailsPackingColCounter
(AvizNo, CreationDate, PCName)
OUTPUT
Inserted.COLNO
VALUES
(:AOrderID,getdate(),:CurrentUser)
ClearOrderColliData
Call to reset the colli data for an order.
Declaration:
Procedure ClearOrderColliData(aOrderID : int64);
Delete from OutDetailsPacking where (AvizNo=:AOrderID);
ConfirmColliOrder
Call to confirm a colli packaged order.
Declaration:
Procedure ConfirmColliOrder(aOrderID : int64)
Select
Artcode,Count(*) as thecount
FROM
OutDetailsPacking
where
(AVIZNO=:AOrderID)
UPDATE OUTDETAILS SET
checkedqty=:TheCount,
CHECKEDBY=:CurrentUser,
CHECKEDDATE=GetDate(),
CHECKEDTIME=GetTime()
WHERE
(Avizno=:OrderID)
AND (ARTCODE=:ArtCode)
AND isnull(CheckedBy,'')=''
PrepareColliPackingListData
Call to prepare printing of colli packing list.
Declaration:
Procedure PrepareColliPackingListData(aOrderID : int64)
UPDATE OutDetailsPacking SET
OutDetailsPacking.OriginalImpRow=OutDetails.OriginalImpRow,
OutDetailsPacking.UnitPrice=cast(
Right(Left(OutDetails.OriginalImpRow,164), 5)+'.'+
Right(Left(OutDetails.OriginalImpRow,166), 2) as numeric(12,2) ),
OutDetailsPacking.UnitListPrice=cast(
Right(Left(OutDetails.OriginalImpRow,175), 5)+'.'+
Right(Left(OutDetails.OriginalImpRow,177), 2) as numeric(12,2) ) ,
OutDetailsPacking.ContactPerson=LTRIM(Right(Left(OUT.OriginalImpRow2, 301), 50)),
OutDetailsPacking.Phone=LTRIM(Right(Left(OUT.OriginalImpRow2, 321), 20)),
OutDetailsPacking.Fax=LTRIM(Right(Left(OUT.OriginalImpRow2, 341), 20)),
OutDetailsPacking.Language=LTRIM(Right(Left(OUT.OriginalImpRow2, 351), 10)),
OutDetailsPacking.Currency=LTRIM(Right(Left(OUT.OriginalImpRow2, 361), 10))
FROM
OutDetailsPacking
INNER JOIN Out on (OutDetailsPacking.Avizno=Out.Aviz)
INNER JOIN OutDetails on
(OutDetailsPacking.Avizno=Outdetails.Avizno)
and (OutDetailsPacking.Artcode=Outdetails.Artcode)
WHERE
OutDetailsPacking.AVIZNO=:orderID
GetEDISerialNo
Call to get a new EDI message serial number.
Declaration:
Function GetEDISerialNo(Const aFileType : string; aFileDate : TDateTime) : Integer;
CancelOrder
Call to cancel an outgoing orders pick&Pack info.
Remark This has a lot of code in common with DeleteDelivery. Factor out common code.
Procedure CancelOrder(Const aOrderID : int64)
DELETE FROM OUTDETAILS
WHERE AVIZNO=:OrderID;
DELETE FROM OUTDETAILSCC
WHERE AVIZNO=:OrderID;
DELETE FROM OUT
WHERE AVIZNO=:OrderID;
UserHistory(:OrderNo, 'ORDER', 'ORDER COMPLETELY DELETED', 'PICK AND PACK MENU');
DeleteOutBlock
Call to delete a block of OUT (shipping) orders.
Declaration:
Function DeleteOutBlock(Const BlockNo : string) : Integer;
INSERT INTO DELHISTORY(CPERSON, DELDATE, DELHOUR, BLOCKNO)
VALUES (:CPERSON, :DELDATE, :DELHOUR, :BLOCKNO)
WHERE OrderNo in (SELECT AVIZ FROM OUT WHERE (BLOCKNO=:BlockNO))
2. Records are updated in **NRW_OUT**:
WHERE ShipmentNumber in (SELECT AVIZ FROM OUT WHERE (BLOCKNO=:BLOCKNO))
3. Records are updated in **XML_OUT**:
WHERE OrderNo in (SELECT AVIZ FROM OUT WHERE (BLOCKNO=:BLOCKNO))
4. Records are deleted from **OUTDETAILS**:
5. Records are deleted from **OUTDETAILSCC**:
5. Records are deleted from **OUT**:
The result is the number of deleted rows from OUT (RowsAffected)
6. The action is listed in the userhistory (auditing API):
#### DeleteDelivery
Call to delete a delivery order.
**Declaration:**
```delphi
Procedure DeleteDelivery(Const aOrderID : Int64);
DELETE FROM OUTDETAILS
WHERE
AVIZNO = :AVIZNO;
DELETE FROM OUTDETAILSCC
WHERE
AVIZNO = :AVIZNO;
DELETE FROM INVDETAILSCC
WHERE
(INVOICE = :AVIZNO)
AND (TRANSACTIONTYPE='Correction');
AND (COMMENTS='Correction for order : '+:AvizNO)
DELETE FROM OUT
WHERE
AVIZ = :AVIZNo;
UserHistory(AVIZ, 'ORDER', 'ORDER COMPLETELY DELETED', 'ORDER MENU');
AddArticleToOrder
Call to add an article to a delivery order.
Declaration:
Function AddArticleToOrder(aOrderID : int64; AArticle: TArticleDescriptor) : Integer;
- let AskedQty equal AArticle.Quantity.
- let Qty equal AArticle.Quantity.
- if StockCode = 75, then the quantity is checked against available quanity:
if this is less than AskedQty, then Qty is reduced to the available quantity.
SELECT isnull(sum(QTY), 0) from FSTOCTOTALCC(:ArticleID);
- Pick locations are selected for the order from the following query, see kitting service, (AvailableArticles). The AdditionalJoin macro is replaced by:
inner join PickTable S ON
(A.STOCKCODE=S.PKSTOCKCODE)
AND (A.LOCATION=S.PKLOCATION)
AND isnull(A.ExpiryDate, '2000-01-01')=isnull(S.PKExpiryDate, '2000-01-01')
AND isnull(A.LOTNO, '')=isnull(S.PKLOTNO, '')
AND (S.JobID=:JobID)
INSERT INTO OUTDETAILS
(AVIZNO, ARTCODE, QTYASKED, QTY, COMMENTS,
INVOICENO, STOCKCODE, ROWNO, PCNAME, FILLDATE, LSBFILE,
FILLTIME, QTYSOFT, TransactionType)
VALUES (
(:AVIZNO, :ARTCODE, :QTYASKED, :Qty, :Comment
:INVOICENO, :STOCKCODE, :ROWNO, :PCNAME, GetDate(), 'MANUAL FILL',
:FILLTIME, :QtySoft, 'ORD')
- The PickTable job is removed from the pick table.
- The result is the number of articles inserted in the order.
GetOrderPickedCheckedCounts
Call to prepare statistics for the MarkOrderPickedChecked call;
declaration:
Function GetOrderPickedCheckedCounts (aOrderID : int64) : TPickPackCounts;
select
SUM(CASE WHEN QTYCF<>QTY THEN 1 ELSE 0 END) AS PickedQtyDiff,
SUM(CASE WHEN CheckedQTY<>QTY TNEN 1 ELSE 0 END) AS CheckedQtyDiff,
SUM(CASE WHEN PICKEDBY='' THEN 0 ELSE 1 END) AS NotPickedCount,
SUM(CASE WHEN CHECKEDBY='' THEN 1 ELSE 0 END) AS NotCheckedCount,
FROM
OUTDETAILS
WHERE
(AVIZNO=:OrderNO)
MarkOrderPickedChecked
Call to mark not yet picked and packed items in order as picked and packed.
declaration:
Procedure MarkOrderPickedChecked(aOrderID : int64);
UPDATE OUTDETAILS SET
qtycf=qty,
PICKEDBY=:CurrentUser,
PICKEDBY2=:CurrentUser,
DATACF=GetDate(),
TIMECF=GetDate()
WHERE
(PICKEDBY='')
AND (AVIZNO=:OrderNo)
UPDATE OUTDETAILS SET
checkedqty=qty,
CHECKEDBY=:CurrentUser,
CHECKEDDATE=GetDate(),
CHECKEDTIME=GetDate()
WHERE
(CHECKEDBY='')
AND (AVIZNO=:OrderNo)
UserHistory(:OrderNo, 'ORDER', 'ORDER MARKED AS PICKED AND CHECKED', 'PICK AND PACK MENU');
ResetOrderPickedChecked
Call to mark not picked and packed items in order as not yet picked and packed.
declaration:
Procedure ResetOrderPickedChecked(aOrderID : int64);
UPDATE OUTDETAILS SET
qtycf=qty,
checkedqty=0,
PICKEDBY='',
PICKEDBY2='',
CHECKEDBY='',
DATACF=Null,
TIMECF='',
CHECKEDDATE=Null,
CHECKEDTIME=''
WHERE
AND (AVIZNO=:OrderNo)
UserHistory(:OrderNo, 'ORDER', 'RESET PICKING AND CHECKING FOR THE ORDER', 'PICK AND PACK MENU');
GetOrderTrackingNumber
Call to fetch the order tracking Number, this is the tracking number from table SPIR_ORDER.
declaration:
Function GetOrderTrackingNumber(aOrderID : int64) : String;
Select TRACKINGNUMBER FROM SPIR_ORDER WHERE ORDERNO=:OrderNo
Select TRACKINGNUMBER FROM OUT WHERE AVIZ=:OrderNo
OrderResetScanPickCheck
Call to reset the pick and/or check data for selected scans.
declaration:
Procedure OrderResetScanPickCheck(aOrderID : int64; ScanIDs : TIDArray; Operation : TScanResetOperation);
UPDATE OUTDETAILS SET
-- {fieldlist}
WHERE
(ID IN :ScanIDS)
checkedqty=NULL ,
CHECKEDBY='',
CHECKEDDATE=NULL,
CHECKEDTIME=''
qtycf=NULL,
PICKEDBY='',
PICKEDBY2='',
DATACF=NULL,
TIMECF=''
UserHistory(OrderID, 'LINES', 'RESET FOR '+{Description}, 'PICK AND PACK MENU');
MarkOrdersAsPrinted
Mark selected orders as printed.
declaration:
Procedure MarkOrdersAsPrinted(OrderIDS : TIDArray);
UPDATE OUT SET
PLPrintingDate=GetDate()
WHERE
(AVIZ in :OrderIDs);
AddToPickJob
Add an invoice to trolley pick job.
declaration:
function AddToPickJob(ajobID: Int64; aDescr : TPickjobDescriptor) : Int64;
UPDATE OUT SET
OUT.TLOCATION=:TrolleyLocationID
WHERE
(AVIZ=:InvoiceID);
1. Insert descriptor data in PickJob table using the ID. 1. Returns the jobID.
PickCheckArticleScanned
Executed when an article is scanned.
declaration:
function PickCheckArticleScanned(aDesc : TPickScanDescriptor) : TPickCheckScanResult;
SELECT
aID, NAME, NAME2, EANCODE4, SET1, SET2, B.ARTCODE, GetDate() as CrtDate, Pop_up_flag_del
FROM
ARTICLE A
LEFT OUTER JOIN ARTICLELINK B on A.NAME=B.ARTCODE
WHERE
:aBarCode in (aEANCode, aEANCode1, EANCode2, EANCode2, EANCode4)
Unknown barcode :abarcode.
Select
min(isnull(PICKEDBY, ''))
from
printjob
left join Out on (pjInvoiceFK=oID)
inner join Outdetails on aviz = avizno
inner join invdetails on
(INVDETAILS.ID = OUTDETAILS.INVOICENO)
AND (INVDETAILS.STOCKCODE = OUTDETAILS.STOCKCODE)
AND (INVDETAILS.ARTCODE = OUTDETAILS.ARTCODE)
WHERE
(pjPrintJobID=:printjobid)
-- {PK_ORDER_COND}
AND (OUTDETAILS.ARTCODE = :ArticleID)
AND (OUTDETAILS.STOCKCODE = :StockCode)
AND isnull(invdetails.location=:Location)
AND isnull(invdetails.Lotno=:LotNo)
Article already picked: :Name
Barcode wrong: not the correct article ?
SELECT
SUM(QTYIN - ISNULL(QTYOUT, 0))
FROM
STOCTOTAL A
left outer join ARTICLE B on NAME = ARTCODE,
LOCATION D
WHERE
(A.LOCATION = :Location )
AND (A.LOTNO <> :LotNo)
AND (A.ARTCODE = :ArticleID)
AND (A.LOCATION=D.LOCATION)
HAVING
SUM(QTYIN-ISNULL(QTYOUT, 0))>0
UNION
SELECT
A.QTY
FROM
OUTDETAILS a,
INNER JOIN INVDETAILS b ON
(b.ID = a.INVOICENO)
AND (b.STOCKCODE = a.STOCKCODE)
AND (b.ARTCODE = a.ARTCODE)
INNER JOIN ARTICLE c ON (a.artcode = c.name)
INNER JOIN LOCATION D ON (B.LOCATION = D.LOCATION)
WHERE
(B.LOCATION = :Location)
AND (B.LOTNO <> :LotNo)
AND (B.ARTCODE = :articleid)
AND (pickedby = '')
AND (A.filldate > DateAdd(day - 15, GETDATE()))
ScanTrolleyLocation
Called to check if the scanned trolley location is OK.
Declaration:
Procedure ScanTrolleyLocation(aPrintJobID, aInvoiceID : Int64; const TrolleyLocation : String)
- Check that Trolley location is at least 5 characters long. if not, an exception is raised with message:
The trolley location must at least be 5 characters long.
- Check that no articles from other orders are yet in this trolley location:
If the count>0, an exception is raised:
Select count(*) from pickjob LEFT JOIN OUT on (aviz=pjInvoiceFK) WHERE (PickJobID=:PickJobID) AND (AVIZ<>InvoiceID) AND (TLOCATION=:TrolleyLocation);
This Trolley Location is used for another order. Please select a new Location.
- Set the trolley location for the selected order:
UPDATE OUT SET TLOCATION = Trolleylocation WHERE (AVIZ = :aInvoiceID )
SaveArticleScanData
Called when an article was scanned for picking, to end picking operation and save results. (sample code see scanner, unit9 Savecandata AND edit3KeyPress)
Declaration:
Function SaveArticleScanData(aDesc: TArticleScanDataDescriptor) : TSaveScanResult;
Desc.singlerow=true
, the following SQL executed if the invoice does not start with KG
:
UPDATE OUTDETAILS SET
OUTDETAILS.qtycf=:Quantity,
OUTDETAILS.TransitLocation=:TranslitLocation,
OUTDETAILS.PICKEDBY=:UserID,
OUTDETAILS.PICKEDBY2=:UserID,
OUTDETAILS.DATACF=GetDate(),
OUTDETAILS.TIMECF=GetDate(),
checkedqty=:Quantity,
CHECKEDBY=:UserID,
CHECKEDDATE=getdate(),
CHECKEDTIME=gedate(),
OUTDETAILS.PickingLocation=:locationID
from
pickjob,
INNER JOIN Out ON (pjInvoiceFK=AVIZ)
INNER JOIN Outdetails on (aviz=avizno)
WHERE
{PK_ORDER_COND}
AND OUTDETAILS.ARTCODE=:article
AND OUTDETAILS.ID=:outdetailsid
Desc.singlerow=true
, the following SQL is executed if the invoice starts with KG
:
UPDATE OUTDETAILS SET
OUTDETAILS.qtycf=:Quantity,
OUTDETAILS.TransitLocation=:TranslitLocation,
OUTDETAILS.PICKEDBY=:UserID,
OUTDETAILS.PICKEDBY2=:UserID,
OUTDETAILS.DATACF=GetDate(),
OUTDETAILS.TIMECF=GetDate(),
OUTDETAILS.PickingLocation=:locationID
from
pickjob,
INNER JOIN Out ON (pjInvoiceFK=AVIZ)
INNER JOIN Outdetails on (aviz=avizno)
WHERE
{PK_ORDER_COND}
AND OUTDETAILS.ARTCODE=:article
AND OUTDETAILS.ID=:outdetailsid
Desc.singlerow=false
then the quantities are updated in a loop determined by the following query:
SELECT
ID, qty, QtyCF
from
printjob
inner join Out on (pjInvoiceFK=oud.avizno)
inner join Outdetails on aviz = avizno
inner join invdetails on INVDETAILS.ID = OUTDETAILS.INVOICENO AND INVDETAILS.ARTCODE = OUTDETAILS.ARTCODE
WHERE
(pjPrintjobID=:printjobid)
AND (OUTDETAILS.ARTCODE = :articleID)
AND (OUTDETAILS.STOCKCODE = :StockCode)
AND (invdetails = :LocationID)
AND (invdetails.Lotno = :LotNo)
AND isnull(OUTDETAILS.PICKEDBY=:UserID)
order by
outdetails.ID asc
rquantity
) is set to desc.quantity
2. For each row, calculate uquantity= min(rquantity,Qty)
where qty
is the value of the field in the current record in the loop.
2. Subtract uquantity
from rquantity
.
2. Update the outdetails record with the following query if the invoice does not start with 'KG'
UPDATE OUTDETAILS SET
OUTDETAILS.qtycf=:Quantity,
OUTDETAILS.TransitLocation=:TranslitLocation,
OUTDETAILS.PICKEDBY=:UserID,
OUTDETAILS.PICKEDBY2=:UserID,
OUTDETAILS.DATACF=GetDate(),
OUTDETAILS.TIMECF=GetDate(),
checkedqty=:Quantity,
CHECKEDBY=:UserID,
CHECKEDDATE=getdate(),
CHECKEDTIME=gedate(),
OUTDETAILS.PickingLocation=:locationID
from
pickjob,
INNER JOIN Out ON (pjInvoiceFK=AVIZ)
INNER JOIN Outdetails on (aviz=avizno)
WHERE
OUTDETAILS.ID=:outdetailsid
outdetalsid
is the value of the ID field from the current record in the loop.
2. Update the outdetails record with the following query if the invoice starts with 'KG'
UPDATE OUTDETAILS SET
OUTDETAILS.qtycf=:Quantity,
OUTDETAILS.TransitLocation=:TranslitLocation,
OUTDETAILS.PICKEDBY=:UserID,
OUTDETAILS.PICKEDBY2=:UserID,
OUTDETAILS.DATACF=GetDate(),
OUTDETAILS.TIMECF=GetDate(),
OUTDETAILS.PickingLocation=:locationID
from
pickjob,
INNER JOIN Out ON (pjInvoiceFK=AVIZ)
INNER JOIN Outdetails on (aviz=avizno)
WHERE
OUTDETAILS.ID=:outdetailsid
SaveScanHistory('PICK', :InvoicblockeID, ArticldeID, Quantity,Location, stockcode, PickjobID)
result.LocationEmptyStock
from this query:
With XXX as (
Select
A.ARTCODE,
A.ID,
isnull(A.QTY, 0) - isnull(SUM(B.QTY), 0) as QTY
from
dbo.INVDETAILS A
LEFT OUTER JOIN dbo.OUTDETAILS B ON
(A.ID = B.INVOICENO)
and (A.ARTCODE = B.ARTCODE)
and isnull(B.TRANSACTIONTYPE, '') = 'ORD'
AND (B.pickedby<>'')
where
A.LOCATION = :LocationID
AND A.ARTCODE=:ArticleID
GROUP BY
A.ARTCODE,
A.ID,
isnull(A.QTY, 0)
HAVING
isnull(A.QTY, 0) - isnull(SUM(B.QTY), 0) <> 0
)
Select
isnull(sum(QTY), 0)
from
XXX
result.LocationEmptyStock
is true
.
1. Calculate result.PickJobDone
from query:
SELECT
count(*)
FROM
pickjob
inner join out A on (pickjob.pjInvoiceFK=a.aviz)
inner join outdetails B ON A.AVIZ=B.AVIZNO
WHERE
(pjPickJobID=:PickJoBID)
and isnull(pickedby, '')=''
result.PickJobDone
is true
.