Kitting
Service Kitting
Synopsis
Service for the controlling of kitting.
Service Data structures
- record TKitOrderDescriptor
- SupplierID (int64) The ID of the supplier of the article.
- MasterCode (String) master article code.
- StockCode (String) Stock code for the new article.
- Quantity (Integer) Quantity to be created.
- LocationID (int64) Optional location to pick from.
-
Comment (String) Optional comment to add.
-
record TKitOrderResult
- OrderID (int64) ID of created record.
-
Warning (String) a warning to be displayed to the user.
-
record TMoveKitToStockDescriptor
- KitOrderID (int64)
- Quantity (Integer)
- LocationID (int64)
- ExpiryDate (TDateTime)
- LotNo (string)
Service Calls
CreateKitOrder
- Creates a kit order in the system.
Declaration:
Function CreateKitOrder(aOrder : TKitOrderDescriptor) : TKitOrderResult;
SELECT NAME From SUPPLIERS where (ID=:SupplierID)
INSERT INTO CGROUP (ARTCODE, QTY, STOCKCODE, CREATIONDATE, SUPPLIER, SUPPLIERID, PCNAME, StockOperated, COMMENTS)
VALUES (:ARTCODE, :QTY, :STOCKCODE, GetDate(), :SUPPLIER, :SUPPLIERID, :PCNAME, 'Y', :COMMENTS)
Param | Source |
---|---|
ARTCODE | aOrder.MasterCode |
QTY | aOrder.Quantity |
StockCode | aOrder.StockCode |
SUPPLIER | Supplier name |
SupplierID | aOrder.SupplierID |
PCNAME | Currently logged in user |
COMMENTS | aOrder.Comment |
The ID of the newly inserted record must be kept (KitID) and returned in the Result.orderID.
- Insert the details of the kit in CGROUPDET:
INSERT INTO CGROUPDET (IDNO, ARTCODE, UNITQTY, STOCKCODE) SELECT DISTINCT :KitID, LinkedArtcode, QTY , :StockCode FROM ArticleLink WHERE (ARTCODE=:MasterCode)
- Get a new block ID for the out blocks:
Add 1 to result (BlockNO).
SELECT MAX(BLOCKNO) FROM OUT
- Create order
With parameters:
INSERT INTO OUT (AVIZ, DATA, CLIENT, BLOCKNO, FILENAME, PCNAME, FILLDATE, IDCLIENT, COUNTRY, OrderType) VALUES (:AVIZ, GetDate(), :CLIENT, :BLOCKNO, 'KIT ORDER', :PCNAME, GetDate(), :IDCLIENT, 'LCW', '000')
Param | Source |
---|---|
AVIZ | 'KG'+KitID |
CLIENT | Supplier name |
BLOCKNO | BlockNo |
PCNAME | Currently logged in user |
IDCLIENT | aOrder.SupplierID |
For each article in the kit, take it from stock and add it to the order. Articles in kit:
SELECT DISTINCT
A.LinkedARTCODE as Artcode, A.QTY as UNITQTY
FROM
ArticleLink A
WHERE
(ARTCODE = :MasterCode)
ORDER BY
ARTCODE
With ART As (
SELECT
INVOICE, A.ARTCODE, A.LOCATION, A.QTY AS QTYIN, A.STOCKCODE, A.FILLDATE, A.ID,
isnull(C.SQ, '99') as MyPRIORITY,
ISNULL(A.ExpiryDate, '1900-01-01') as EXPIRYDATE,
Right(' '+isnull(A.LotNo, ''), 1) as LotPriority,
(CASE WHEN isnull(C.HighPriorityForPick, 'N')='Y' THEN 0 ELSE 1 END) AS HighPrSQ,
(CASE WHEN RIGHT(A.LOCATION, 1)='A' THEN 0 ELSE 1 END) AS LocationLevelPriority,
(CASE
WHEN EXPIRYDATE IS NULL THEN 3
WHEN EXPIRYDATE IS not NULL and DateAdd(Day, -240, ExpiryDate)>GetDate() THEN 2
WHEN EXPIRYDATE IS not NULL and DateAdd(Day, -240, ExpiryDate)<=GetDate() AND EXPIRYDATE>GETDATE() and isnull(AExpFirst,'N')<>'Y' THEN 1
WHEN EXPIRYDATE IS not NULL and DateAdd(Day, -240, ExpiryDate)<=GetDate() AND EXPIRYDATE>GETDATE() and isnull(AExpFirst,'N')='Y' THEN 4
WHEN EXPIRYDATE IS not NULL and ExpiryDate<=GetDate() THEN 0
ELSE 1
END) AS ExpirySQ
FROM
INVDETAILS A
INNER JOIN ARTICLE D ON (A.ARTCODE=D.NAME)
INNER JOIN LOCATION C ON (A.LOCATION=C.LOCATION)
-- {AdditionalJoin}
WHERE
(A.ARTCODE = :ArticleCode)
AND (A.STOCKCODE = '75')
AND isnull(C.NotForPicking,'')<>'Y'
AND (C.NotForPicking<>'Y')
-- AND {LocationFilter}
)
SELECT
ART.*,
ART.QTYIN-isnull(SUM(B.QTY), 0) as QTY
FROM
ART
LEFT OUTER JOIN OUTDETAILS B ON (ART.ID=B.INVOICENO)
WHERE
ExpirySQ<>0
GROUP BY
ART.INVOICE, ART.ARTCODE, ART.LOCATION , ART.COLOR, ART.QTYIN, ART.AMBALAJ, ART.STOCKCODE, ART.FILLDATE, ART.ID,
ART.MYPRIORITY, ART.ExpiryDate, ART.LotPriority, ART.HighPrSQ,ART.ExpirySQ, Art.LocationLevelPriority
HAVING
ART.QTYIN-isnull(SUM(B.QTY), 0) > 0
ORDER BY
ExpirySQ DESC, EXPIRYDATE ASC, HighPrSQ ASC, LotPriority asc, LocationLevelPriority asc, FILLDATE ASC, MyPRIORITY ASC
(isNull(A.LOCATION,'')<>'')
(A.LOCATION<>:Location)
UsedQty is the quantity still needed to fill the kit, topped by available quantity in the current AvailableArticles line.
The following insert is performed while the asked quantity (QtyAsked = KitQty x GrpQty) is not reached:
INSERT INTO OUTDETAILS
(AVIZNO, ARTCODE, QTYASKED, QTY, AMBALAJ, COMMENTS,
OLDAMB, COLOR, INVOICENO, STOCKCODE, ROWNO, PCNAME, FILLDATE, LSBFILE,
FILLTIME, QTYSOFT, TransactionType)
VALUES
(:AVIZNO, :ARTCODE, :QTYASKED, :QTY, '' :COMMENTS,
'', '', :INVOICENO, '75', :ROWNO, :PCNAME, GetDate(),'KIT ORDER',
:FILLTIME, :QTYSOFT, ''KIT'')
Where the parameters are filled as follows:
Param | Source |
---|---|
AVIZNO | 'KG'+KitID |
ARTCODE | Current article |
QtyAsked | UniqQTY*GrpQty |
Qty | UsedQty or 0 |
COMMENTS | Empty or 'Not delivered because stock is 0' |
INVOICENO | AvailableArticles.QTY |
ROWNO | Kit Article Loop counter (1-based) |
PCNAME | Currently logged in user |
LSBFILE | KIT ORDER |
FILLTIME | Current time in hh:nn format |
QTYSOFT | UsedQty or 0 |
CLIENT | Supplier name |
BLOCKNO | BlockNo |
PCNAME | Currently logged in user |
The loop maintains a QtySupplied counter, which is the amount of articles actually supplied.
If there were not enough articles on stock (QtySupplied < QtyAsked), then a warning message is attached to the result:
Voor artikel :CODE zijn :Qty gevraagd, maar er waren slechts :QtySupplied artikels beschikbaar.
For every kit article line where QtySupplied is nonzero, the StockControl.OperateStockCC is called: * Aviz is 'KG'+KitID * Qty is QtySupplied * Supplier is empty. * StockCode is 99.
CheckKitOrderPossible
Check if a kitting order is possible. It returns a list of errors. All possible errors are returned.
Declaration:
Function CheckKitOrderPossible(Const ArtCode,aStockCode : String; AQty : Integer) : TStringArray;
SELECT
count(*) as TheCount
FROM
articlelink
WHERE
(ARTCODE=:ArtCode)
This article :ArtCode is missing parts.
Select
LINKEDARTCODE
from
articlelink L
LEFT JOIN ARTICLE A ON (A.NAME=L.LINKEDARTCODE)
WHERE
(L.ARTCODE=:ArtCode)
AND (L.LINKEDARTCODE is NULL)
Unknown article in this composition:
:ArticleList
Please register the articles.
SELECT
SUM(ISNULL(QTYIN,0)-ISNULL(QTYOUT, 0)) as QtyAvail
B.LinkedARTCODE
FROM
articlelink B
LEFT OUTER JOIN STOCTOTAL A ON
(A.ARTCODE=B.LINKEDARTCODE)
AND (A.STOCKCODE=:StockCode)
INNER JOIN Location C on (A.LOCATION=C.LOCATION) AND (isnull(C.NotForPicking,'')<>'Y')
WHERE
(B.ARTCODE = : Artcode)
AND (CASE WHEN EXPIRYDATE IS not NULL and DateAdd(Day, -240, ExpiryDate)<=GetDate()
THEN 0
ELSE 1 END)=1
GROUP BY
B.LinkedARTCODE
No stock available for :LinkedArticle
Article :ArtCode has insufficint stock: **QtyAvail**
SELECT
isnull(SUM(isnull(A.QTY, 0)), 0) as QtyAvail,
B.LinkedARTCODE
FROM
articlelink B
LEFT OUTER JOIN STOCTOTALCC A on
(A.ARTCODE=B.LINKEDARTCODE) and (A.STOCKCODE='99')
WHERE
(B.ARTCODE =: Artcode)
GROUP BY
B.LinkedARTCODE, B.QTY
No customs-cleared stock available for :LinkedArticle
Not enough customs-cleared stock available for :LinkedArticle
DeleteKitOrder
Delete all information related to a kit.
Declaration:
Procedure DeleteKitOrder(Const aKit : Integer; const aMoveLocation : String);
SELECT
B.ARTCODE, B.STOCKCODE, B.LOCATION, A.QTY, B.LOTNO, B.ID INTO tmpMoveDelKit
FROM
OUTDETAILS A
INNER JOIN INVDETAILS B on (A.InvoiceNo=B.ID)
WHERE
(A.AVIZNO='KG'+:ID)
DELETE FROM INVDETAILS WHERE (INVOICE=:KitID);
DELETE FROM INVDETAILSCC WHERE (INVOICE=:KitID);
DELETE FROM INV WHERE (INVOICE=:KitID);
DELETE FROM OUTDETAILS WHERE (AVIZNO=:KitID);
DELETE FROM OUTDETAILSCC WHERE (AVIZNO=:KitID);
DELETE FROM OUT WHERE (AVIZ=:KitID);
DELETE FROM CGROUPDET WHERE (IDNO=:ID);
DELETE FROM CGROUP WHERE (ID=:ID);
AssignMasterLotNo
Assign a master LotNo to a kit order.
Declaration:
Function AssignMasterLotNo(aKitID : Integer) : String;
SELECT
min(A.ExpiryDate) AS ExpDate,
A.ARTCODE
FROM
INVDETAILS A,
INNER JOIN ARTICLE C ON (A.ARTCODE=C.NAME)
INNER JOIN OUTDETAILS B ON (A.ID=B.INVOICENO)
WHERE
(B.AVIZNO='KG'+:aKitID)
AND (A.ExpiryDATE is not null)
GROUP BY
EXPIRYTIME, A.ARTCODE
ORDER BY
ExpDate asc
the ExpDate field is not null, the basis of the lot number is composed of:
DecodeDate(ExpDate,Y,M,D);
MyExpExt:='L'+char(ord('A')+M-1)+IntToStr(MyExpYear);
SELECT
count(*) as acount, Max(MLOTNO) as aMax
FROM
CGROUP
WHERE
MLOTNO LIKE :MyExpExt
Result:=MyExpExt+Format('%.4d',[aMax+1])
UPDATE
CGROUP
SET MLOTNO=:LOTNO
MExpiryDate=:MyExpiryDate
WHERE
(ID=:aKitID)
MarkAsChecked
This will mark outgoing orders as checked by the current user.
Declaration:
Procedure MarkAsChecked(aKitID : Integer);
UPDATE OUTDETAILS SET
checkedqty=qtycf,
CHECKEDBY=:CurrentUser
CHECKEDDATE=GetDate(),
CHECKEDTIME=:CheckedTime,
WHERE
(AVIZNO=:AVIZNO)
AND isnull(CheckedBy,'')=''
ChangeKitQuantity
This will change the quantity of the kit
Declaration:
Procedure ChangeKitQuantity(aKitID : Integer; ANewQty : Integer);
The quantity :ANewQty exceeds the current quantity: :Qty
UPDATE CGROUP SET
QTY=:aNewQty
where
(ID=:aKitID)
ChangeKitArticleQuantity
This will change the master quantity of an article in the kit
Declaration:
Procedure ChangeKitArticleQuantity(aKitID,aLineId : Integer; ANewQty : Integer);
The quantity :ANewQty exceeds the current quantity for :Article: :Qty
if the new article quantity is OK, the following are executed
UPDATE OUTDETAILS SET
QTY=:aNewQty
QTYSOFT=:aNewQty
where
(ID=:aLineID)
UPDATE OUTDETAILS SET
QTYCF=:aNewty
WHERE
(ID=:aLineID) AND (ISNULL(PICKEDBY, '')<>'')
MoveKitToStock
This will move part of the prepared kit to the stock.
Declaration:
Procedure MoveKitToStock(desc : TMoveKitToStockDescriptor);
SELECT
DISTINCT B.ArtCode,
A.ExpiryDATE,
A.Lotno,
D.UnitQTY,
sum(B.QTY) AS QTY,
sum(B.QTYCF) AS PK_QTY
FROM
INVDETAILS A
INNER JOIN OUTDETAILS B ON A.ID = B.INVOICENO
INNER JOIN CGROUP C ON 'KG' + CAST (C.ID AS VARCHAR (15)) = B.AVIZNO
INNER JOIN CGROUPDET D ON (B.ARTCODE = D.ARTCODE) AND (C.ID = D.IDNO)
WHERE
B.AVIZNO = :KitOrder
AND (pickedby <> '')
AND (checkedby = '')
GROUP BY
B.ArtCode,
A.ExpiryDATE,
A.Lotno,
D.UnitQTY
ORDER BY
B.ARTCODE,
A.Lotno ASC
- If no INV exists for KitOrder:
insert a new order:
SELECT count(*) from INV where (INVOICE=:KitOrder)
insert into INV (INVOICE, DATA, SUPPL, PCNAME, FILLDATE, DEP) Select DISTINCT :Invoice,getDate(),Supplier, :UserName,Now,'KIT' FROM CGROUP WHERE ('KG'+CAST(ID AS VARCHAR(15))=:KitOrder)
-
Set the requested quantity (QtyRequested) to the kit qty * article quantity. Run a second loop:
The ArtCode parameter value comes from the field in loop 1 and the lotno parameter valie also from the field in loop 1.SELECT A.ID, A.QTY as QtyStock, A.QTYCF From outdetails A Inner join INVDETAILS B ON A.INVOICENO=B.ID where (A.avizno=:OrderID) AND (A.ARTCODE=:ArtCode) AND (B.LOTNO=:LotNo) and checkedby=''
-
While requested quantity is positive, run the loop:
-
if the requested quantity is strictly less than the stock quantity from the second loop line, then the detail line is split in 2 lines: one with requested quantity, one with remaining quantity.
- Update existing line to match requested quantity:
UPDATE OUTDETAILS
SET
QTY=:QtyRequested,
qtycf=:QtyRequested,
qtySOFT=:QtyRequested,
checkedqty=:QtyRequested,
CHECKEDBY=:CurrentUser,
CHECKEDDATE=:GetDate(),
CHECKEDTIME=:GetDate()
WHERE ID=:ID
INSERT INTO OUTDETAILS
(AVIZNO, ARTCODE, QTYASKED, QTY, AMBALAJ, COMMENTS,
OLDAMB, COLOR, INVOICENO, STOCKCODE, ROWNO, PCNAME, FILLDATE, QTYCF, DATACF, LSBFILE, FILLTIME,
BPOINTS, QTYSOFT, UNITVALUE, CURENCY, TotalValue, TCurency, PICKEDBY, MODIFYQTY, MODIFY, TIMECF,
LSBDATE, LSBTIME, CHECKEDQTY, CHECKEDBY, CHECKEDDATE, CHECKEDTIME, PICKEDBY2, COLNO, COLQTY, COLDATE,
TransactionType, TransitLocation
)
SELECT
AVIZNO, ARTCODE, QTYASKED, :RemainingQty, AMBALAJ, COMMENTS,
OLDAMB, COLOR, INVOICENO, STOCKCODE, ROWNO, PCNAME, FILLDATE, :RemainingQty, DATACF, LSBFILE, FILLTIME,
BPOINTS, :RemainingQty, UNITVALUE, CURENCY, TotalValue, TCurency, PICKEDBY, MODIFYQTY, MODIFY, TIMECF,
LSBDATE, LSBTIME, NULL, NULL, NULL, NULL, PICKEDBY2, COLNO, COLQTY, COLDATE,
TransactionType, TransitLocation
FROM
OUTDETAILS
WHERE
(ID=:ID)
-
If the requested quantity is larger or equal to stock quantity, update existing line:
subtract QtyStock from requested quantity.UPDATE OUTDETAILS SET QTY=:QtyStock, qtycf=:QtyStock, qtySOFT=:QtyStock, checkedqty=:QtyStock, CHECKEDBY=:CurrentUser, CHECKEDDATE=:GetDate(), CHECKEDTIME=:GetDate() WHERE ID=:ID
-
The prepared kit quantity must be entered in the stock. Execute:
INSERT INTO INVDETAILS ( INVOICE, ARTCODE, QTYIN, QTY, LOCATION, SUPPLIER, STOCKCODE, PCNAME, FILLDATE, ExpiryDate, LotNo, TransactionType ) Select DISTINCT :KitOrderID, artcode, :Quantity, :Quantity, :Location, Supplier, STOCKCODE, :CurrentUser,GetDate(), :ExpiryDate, :LotNo, 'KIT' FROM CGROUP WHERE 'KG'+CAST(ID AS VARCHAR(15))=:KitOrderID
-
Prepared kit must be inserted in customs-cleared stock:
INSERT INTO INVDETAILSCC ( INVOICE, ARTCODE, QTY, STOCKCODE, SUPPLIER, PCNAME, FILLDATE, TransactionType ) Select DISTINCT :KitOrderID, ARTCODE, :Quantity, '99', Supplier, :CurrentUser, GetDate(), 'KIT' FROM CGROUP WHERE 'KG'+CAST(ID AS VARCHAR(15))=:KitOrderID
-
Update kit definition to reflect new available quantity. Execute:
UPDATE CGROUP SET READYQTY = READYQTY + :Quantity WHERE 'KG'+CAST(ID AS VARCHAR(15))=:OrderID