SUBROUTINE CMSD.INV.MASTER(IMA.DATA) *---------------------------------------------------------------------- *PGM NAME: CMSD.INV.MASTER *PURPOSE: PERFORM ALL INVENTORY UPDATES - RETURN PASS/FAIL RESULT *AUTHOR: BARKSDALE *CREATED: 08/12/94 *---------------------------------------------------------------------- * * BEWARE!!! This program performs all updates which affect quantity * available and physical quantity to inventory including transaction * detail and summarized activity (historical record-keeping) for any * inventory item. It is called from a significant number of programs * system-wide as well as from itself (recursive). Please exercise * EXTREME CAUTION when making additions or changes to code contained * herein! * *--explanation of reject reason codes: * 1 - quantity is zero or null * 2 - invalid date * 3 - cannot assemble non-assembled items * 4 - transactions not valid against assembled items * 5 - invalid warehouse * 6 - transfers must be reductions to FROM warehouse (negative qty) * 7 - transfers must have valid TO warehouse * 8 - inventory item not on file * 9 - insufficient quantity available * 10 - item has backorders waiting for release * 11 - cannot assemble sufficient quantity * *--include data $INCLUDE GEN.COMMON $INCLUDE IMA $INCLUDE IVT $INCLUDE INV $INCLUDE IA $INCLUDE IC * *--initialize tables READ WHSE.CODES FROM GEN.KEYS,"WAREHOUSE.CODES" ELSE WHSE.CODES="" READ TYPE.CODES FROM GEN.KEYS,"INVTRANS.TYPE" ELSE TYPE.CODES="" * *--initialize other variables READU NEXT.JRNL FROM GEN.KEYS,"NEXT.INV.JOURNAL" THEN NEXT.JRNL=NEXT.JRNL+1 END ELSE NEXT.JRNL=1 END WRITE NEXT.JRNL ON GEN.KEYS,"NEXT.INV.JOURNAL" EQU TRUE TO 1 EQU FALSE TO 0 * *---- * Check to see if IMA.DATA contains all the necessary data to * perform update to inventory and verify validity of several * of the fields. *---- REJECT=FALSE REJECT.REASON="" CHANGED.FIELDS="" *---- * Log error in case of ultimate failure to update in any capacity * by the calling program. For example: * - this program was unable to read the inventory item * - the calling program is not defining IMA.DATA properly *---- IF IMA.DATA="REPORT.ERROR" THEN GO 100000 READ IREC FROM INVENTORY,IMA.DATA THEN IF IREC="N" THEN INXFLAG=TRUE END ELSE INXFLAG=FALSE END IF IREC="Y" THEN ASMFLAG=TRUE END ELSE ASMFLAG=FALSE END IF IMA.DATA="" OR IMA.DATA=0 THEN IF IMA.DATA="PO.ADD" OR IMA.DATA="PO.DELETE" ELSE *--zero or null would be valid only if change PO E.T.A. REJECT=TRUE REJECT.REASON=1 END END IF IMA.DATA="" THEN REJECT=TRUE REJECT.REASON=2 END *---- * check to see if valid function *---- BEGIN CASE CASE IMA.DATA="CHECK.AVAILABLE" CASE IMA.DATA="COMMIT" CASE IMA.DATA="UNCOMMIT" CASE IMA.DATA="ADD.BACKORDER" CASE IMA.DATA="DELETE.BACKORDER" CASE IMA.DATA="RELEASE.BACKORDER" CASE IMA.DATA="ASSEMBLE" IF ASMFLAG ELSE REJECT=TRUE;*--may only assemble assembled items REJECT.REASON=3 END CASE IMA.DATA="ASM.ADD" CASE IMA.DATA="PO.ADD" CASE IMA.DATA="PO.DELETE" CASE IMA.DATA="PO.RECEIVE" CASE IMA.DATA="COST.UPDATE" CASE IMA.DATA="RETURN.GOOD" CASE IMA.DATA="RETURN.DAMAGED" CASE IMA.DATA="RETURN.DEFECTIVE" CASE IMA.DATA="REPORT.ERROR" CASE 1 LOCATE(IMA.DATA,TYPE.CODES,1;FND) ELSE REJECT=1 IF ASMFLAG THEN IF IMA.DATA="CMSD.INVTRANS" OR IMA.DATA="CMSD.IVT.MULTI" THEN REJECT=TRUE;*--transactions invalid for assembled item REJECT.REASON=4 END END END CASE IF IMA.DATA="" THEN REJECT=TRUE REJECT.REASON=5 END LOCATE(IMA.DATA,WHSE.CODES,1;FND) ELSE REJECT=TRUE REJECT.REASON=5 END IF IMA.DATA="TRF" THEN IF IMA.DATA > 0 THEN REJECT=TRUE REJECT.REASON=6 END IF IMA.DATA="" THEN REJECT=TRUE REJECT.REASON=7 END LOCATE(IMA.DATA,WHSE.CODES,1;FND) ELSE REJECT=TRUE REJECT.REASON=7 END END END ELSE REJECT=TRUE REJECT.REASON=8 END IF REJECT THEN GO 100000 * *--initialize variables MINUS=-1 ITEM=IMA.DATA QTY=IMA.DATA YEAR=OCONV(IMA.DATA,"DY") MONTH=OCONV(IMA.DATA,"DM")'R%2' ACTION=IMA.DATA IF ACTION="ASM.ADD" THEN ACTION="ASM" TYPE=ACTION TDATE=IMA.DATA USER=IMA.DATA TREF=IMA.DATA FLOC=IMA.DATA TLOC=IMA.DATA CMNT=IMA.DATA WHSE=IMA.DATA ENTRY.DATE=DATE() EFFPD=YEAR[3,2]:"-":MONTH TREC=''; IREC=''; AREC='' IKEY=ITEM TKEY=EFFPD:'|':ITEM AKEY=YEAR:"|":WHSE:"|":ITEM TYPWHS=TYPE:"|":WHSE:"|":TDATE * *--------------------main program section----------------------------- BEGIN CASE CASE ACTION="CHECK.AVAILABLE" *---- * This is a request to see if sufficient quantity is available to * fulfill a request for an item. It returns a pass/fail result * and is informational only - ABSOLUTELY NO UPDATE to inventory * will occur as a result of this requested action. The purpose for * using this program to simply check availability of an item is to * insure that the verification of availability follows the same * procedural steps as an actual update to inventory and thereby * yields more consistent results. *---- IF QTY < 0 ELSE *--if negative quantity then result is always "PASS" IF INXFLAG ELSE *--if inexhaustible supply then result is always "PASS" IF ASMFLAG THEN GOSUB 7000 IF REJECT THEN REJECT.REASON=11 END ELSE QTY=QTY*MINUS GOSUB 1000 IF REJECT THEN REJECT.REASON=9 END END END CASE ACTION="COMMIT" *---- * This is a request to commit inventory. Quantity should always be * a positive number. An attempt will be made to reduce * INV$QTY.AVAILABLE for item. If quantity available is insufficient * to commit inventory the following other actions will be attempted: * - If INV$ORDER.CODE = "N" then item has an inexhaustible supply * and sufficient quantity will be added to fulfill request. * - If INV$ASSEMBLED = "Y" then item is assembled from components. * An attempt will be made to assemble enough to cover requested * quantity. * If quantity remains insufficient to fulfill request or backorders * already exist for this item then request will be rejected and * the result "FAIL" will be returned to calling program. * "PHYSICAL" quantity remains unaffected regardless of result. *---- IF INXFLAG THEN GOSUB 6000 ;*--inexhaustible supply IF ASMFLAG THEN GOSUB 7000 ;*--assembled item QTY=QTY*MINUS GOSUB 1000;*--deduct from available quantity CASE ACTION="UNCOMMIT" *---- * This is a request to release inventory which has previously been * committed. Quantity should always be a positive number. * INV$QTY.AVAILABLE will be increased. No attempt will be made to * undo updates resulting from inexhaustible supply or assembled * inventory processes. * Result is always "PASS" to a request to uncommit. * "PHYSICAL" quantity remains unaffected. *---- GOSUB 1000;*--add back to available quantity CASE ACTION="ADD.BACKORDER" *---- * This is a request to backorder inventory. Quantity should always * be a positive number. INV$QTY.BACKORDERED will be increased. * Result is always "PASS" to a request to backorder. * "PHYSICAL" quantity remains unaffected. *---- GOSUB 2000;*--add to backorder quantity CASE ACTION="DELETE.BACKORDER" *---- * This is a request to reduce quantity on backorder. Quantity should * always be a positive number. INV$QTY.BACKORDERED will be reduced. * Result is always "PASS" to a request to delete a backorder. * "PHYSICAL" quantity remains unaffected. *---- QTY=QTY*MINUS GOSUB 2000;*--reduce backorder quantity CASE ACTION="RELEASE.BACKORDER" *---- * This indicates backorder is being released to ship. Quantity should * always be a positive number. Both INV$QTY.AVAILABLE and * INV$QTY.BACKORDERED will be reduced. * "PHYSICAL" quantity remains unaffected. *---- IF INXFLAG THEN GOSUB 6000;*--inexhaustible supply IF ASMFLAG THEN GOSUB 7000;*--assembled item QTY=QTY*MINUS GOSUB 1000;*--reduce quantity available IF NOT(REJECT) THEN GOSUB 2000;*--reduce backorder quantity CASE ACTION="ASSEMBLE" *---- * This is a request to assemble a specified quantity of an item * from its component parts. A "PASS" result indicates a reduction * to "PHYSICAL" and "AVAILABLE" quantity for each of the component * items and an offsetting increase to the assembled item itself. * A "FAIL" result indicates at least one of the component items * was on backorder or had insufficient supply to fulfill request. *---- GOSUB 7000 CASE ACTION="PO.ADD" *---- * This is a request to add to the ON ORDER quantity of an item. * Sub-valued data relevant to PO within WHSE will be updated. * All other quantity fields will be unaffected. *---- GOSUB 8000 CASE ACTION="PO.DELETE" *---- * This action will do exactly the same as above except the quantity * will be subtracted from the ON ORDER number for this PO *---- QTY=QTY*MINUS GOSUB 8000 CASE ACTION="PO.RECEIVE" *---- * This action is similar to PO.DELETE accept that ETA will not be * updated. *---- QTY=QTY*MINUS GOSUB 9000 CASE ACTION="COST.UPDATE" *---- * This action signifies an update to the INV.COST file which is * used to calculate unit cost. No quantity fields on the inventory * record are updated *---- GOSUB 10000 CASE ACTION="RETURN.GOOD" CASE ACTION="RETURN.DAMAGED" CASE ACTION="RETURN.DEFECTIVE" CASE ACTION="SLS" *---- * This is a request to record the actual shipment of product to a * customer. INV$QTY.REDUCTIONS will be increased, and appropriate * entries will be recorded in INV.TRANS and INV.ACTIVITY files to * reflect change in "PHYSICAL" quantity. * INV$QTY.AVAILABLE is unaffected by this action. *---- QTY=QTY*MINUS GOSUB 3000;*--create transaction GOSUB 4000;*--reduce physical quantity GOSUB 5000;*--update activity (summary) CASE ACTION="TRF" *---- * This is a request to transfer quantity from one warehouse to * another. It requires that the quantity to be transferred MUST * be available in the FROM warehouse. No attempt is made to * assemble sufficient quantity or to add quantity due to the * inexhaustibility of the item being transferred. * A quantity adjustment will be made to 2 (two) warehouses. * Both "PHYSICAL" and "AVAILABLE" quantity will be updated. *---- GOSUB 1000;*--reduce available quantity - FROM warehouse IF NOT(REJECT) THEN GOSUB 3000;*--create transaction - FROM warehouse IF NOT(REJECT) THEN GOSUB 4000;*--reduce physical - FROM warehouse IF NOT(REJECT) THEN GOSUB 5000;*--update activity - FROM warehouse WHSE=TLOC AKEY=YEAR:"|":WHSE:"|":ITEM QTY=QTY*MINUS IF NOT(REJECT) THEN GOSUB 1000;*--increase available - TO warehouse IF NOT(REJECT) THEN GOSUB 3000;*--create transaction - TO warehouse IF NOT(REJECT) THEN GOSUB 4000;*--increase physical - TO warehouse IF NOT(REJECT) THEN GOSUB 5000;*--update activity - TO warehouse CASE 1 *---- * All other actions are valid inventory transactions which * will affect both the physical and available quantities. *---- IF QTY < 0 AND INXFLAG THEN GOSUB 6000 ;*--inexhaustible supply GOSUB 1000;*--update available quantity IF NOT(REJECT) THEN GOSUB 3000;*--create transaction IF NOT(REJECT) THEN GOSUB 4000;*--update physical quantity IF NOT(REJECT) THEN GOSUB 5000;*--update activity (summary) END CASE GO 100000 ;*--end of program *--------------------------------------------------------------------- * 1000 *---update inventory quantity available READU IREC FROM INVENTORY,ITEM THEN LOCATE(WHSE,IREC,INV$WAREHOUSE;FND;"AR") ELSE IREC=INSERT(IREC,INV$WAREHOUSE,FND;WHSE) IREC=INSERT(IREC,INV$QTY.INCREASES,FND;0) IREC=INSERT(IREC,INV$QTY.REDUCTIONS,FND;0) IREC=INSERT(IREC,INV$QTY.AVAILABLE,FND;0) IREC=INSERT(IREC,INV$QTY.BACKORDERED,FND;0) IREC=INSERT(IREC,INV$QTY.ON.ORDER,FND;"") IREC=INSERT(IREC,INV$EST.TIME.ARRIVAL,FND;"") IREC=INSERT(IREC,INV$PO.NUMBER,FND;"") IREC=INSERT(IREC,INV$ACTIVITY.YEARS,FND;"") IREC=INSERT(IREC,INV$LEAD.TIME,FND;"") IREC=INSERT(IREC,INV$REORDER.POINT,FND;0) IREC=INSERT(IREC,INV$SAFETY.STOCK,FND;0) IREC=INSERT(IREC,INV$EST.MONTHLY.USAGE,FND;0) IREC=INSERT(IREC,INV$PROJECTED.OS.DATE,FND;"") IREC=INSERT(IREC,INV$PRIMARY.LOCATION,FND;"") IREC=INSERT(IREC,INV$ALTERNATE.LOCATION1,FND;"") IREC=INSERT(IREC,INV$ALTERNATE.LOCATION2,FND;"") END IF QTY < 0 THEN LOCATE(ACTION,TYPE.CODES,1;IDX) ELSE IF IREC >= ABS(QTY) ELSE REJECT=TRUE;*--insufficient quantity to fulfill request REJECT.REASON=9 RETURN END QOB=IREC IF QOB > 0 AND ACTION#"RELEASE.BACKORDER" THEN REJECT=TRUE;*--waiting backorders take priority over new orders REJECT.REASON=10 RETURN END END END IREC=IREC+QTY IF ACTION="CHECK.AVAILABLE" ELSE *--do not WRITE if only checking availability IF IREC < 0 THEN CRT @(0,22):CL:BEEP:"Warning! Quantity available for ":ITEM:" is negative - ": *ANY=""; INPUT ANY CHANGED.FIELDS=CHANGED.FIELDS:"-A" END ELSE CHANGED.FIELDS=CHANGED.FIELDS:"A" END WRITE IREC ON INVENTORY,ITEM IF ACTION="COMMIT" OR ACTION="UNCOMMIT" THEN CHANGED.FIELDS=CHANGED.FIELDS:"U" END END END RETURN * 2000 *---update backorder quantity (INVENTORY) READU IREC FROM INVENTORY,ITEM THEN LOCATE(WHSE,IREC,INV$WAREHOUSE;FND;"AR") THEN IREC=IREC+QTY END ELSE IREC=INSERT(IREC,INV$WAREHOUSE,FND;WHSE) IREC=INSERT(IREC,INV$QTY.INCREASES,FND;0) IREC=INSERT(IREC,INV$QTY.REDUCTIONS,FND;0) IREC=INSERT(IREC,INV$QTY.AVAILABLE,FND;0) IREC=INSERT(IREC,INV$QTY.BACKORDERED,FND;0) IREC=INSERT(IREC,INV$QTY.ON.ORDER,FND;"") IREC=INSERT(IREC,INV$EST.TIME.ARRIVAL,FND;"") IREC=INSERT(IREC,INV$PO.NUMBER,FND;"") IREC=INSERT(IREC,INV$ACTIVITY.YEARS,FND;"") IREC=INSERT(IREC,INV$LEAD.TIME,FND;"") IREC=INSERT(IREC,INV$REORDER.POINT,FND;0) IREC=INSERT(IREC,INV$SAFETY.STOCK,FND;0) IREC=INSERT(IREC,INV$EST.MONTHLY.USAGE,FND;0) IREC=INSERT(IREC,INV$PROJECTED.OS.DATE,FND;"") IREC=INSERT(IREC,INV$PRIMARY.LOCATION,FND;"") IREC=INSERT(IREC,INV$ALTERNATE.LOCATION1,FND;"") IREC=INSERT(IREC,INV$ALTERNATE.LOCATION2,FND;"") IREC=QTY END IF IREC < 0 THEN CRT @(0,22):CL:BEEP:"Warning! Quantity backordered for ":ITEM:" is negative - ": *ANY=""; INPUT ANY CHANGED.FIELDS=CHANGED.FIELDS:"-B" END ELSE CHANGED.FIELDS=CHANGED.FIELDS:"B" END WRITE IREC ON INVENTORY,ITEM END RETURN * 3000 *---update inventory transactions (INV.TRANS) READU TREC FROM INV.TRANS,TKEY THEN BEGIN CASE CASE TYPE='SLS' LOCATE(TYPWHS,TREC,IVT$SORT.KEY;WH) THEN TREC=TREC+QTY TREC=TIME() END ELSE GOSUB 3100 END CASE TYPE='RTS' LOCATE(TYPWHS,TREC,IVT$SORT.KEY;WH) THEN IF TREC=TDATE THEN TREC=TREC+QTY TREC=TIME() END ELSE GOSUB 3100 END END ELSE GOSUB 3100 END CASE TYPE='INX' LOCATE(TYPWHS,TREC,IVT$SORT.KEY;WH) THEN TREC=TREC+QTY TREC=TIME() END ELSE GOSUB 3100 END CASE TYPE='ASM' FOUND=FALSE LOCATE(TYPWHS,TREC,IVT$SORT.KEY;WH) THEN LOOP UNTIL TREC#TYPWHS OR FOUND DO IF TREC=CMNT THEN TREC=TREC+QTY TREC=TIME() FOUND=TRUE END WH=WH+1 REPEAT IF NOT(FOUND) THEN GOSUB 3100 END ELSE GOSUB 3100 END CASE 1 GOSUB 3100 END CASE END ELSE TREC=TYPE TREC=QTY TREC=TDATE TREC=TIME() TREC=USER TREC=TREF TREC=FLOC TREC=TLOC TREC=CMNT TREC=ENTRY.DATE TREC=TYPWHS END WRITE TREC ON INV.TRANS,TKEY RETURN * 3100 *----insert new transaction---- LOCATE(TDATE,TREC,IVT$DATE;WH;'DR') THEN NULL TREC=INSERT(TREC,IVT$TYPE,WH;TYPE) TREC=INSERT(TREC,IVT$QUANTITY,WH;QTY) TREC=INSERT(TREC,IVT$DATE,WH;TDATE) TREC=INSERT(TREC,IVT$TIME,WH;TIME()) TREC=INSERT(TREC,IVT$OPERATOR,WH;USER) TREC=INSERT(TREC,IVT$REFERENCE.NUMBER,WH;TREF) TREC=INSERT(TREC,IVT$FROM.LOCATION,WH;FLOC) TREC=INSERT(TREC,IVT$TO.LOCATION,WH;TLOC) TREC=INSERT(TREC,IVT$COMMENT,WH;CMNT) TREC=INSERT(TREC,IVT$ENTRY.DATE,WH;ENTRY.DATE) TREC=INSERT(TREC,IVT$SORT.KEY,WH;TYPWHS) RETURN * 4000 *---update shelf quantity (INVENTORY) IF QTY > 0 THEN IATTR=INV$QTY.INCREASES END ELSE IATTR=INV$QTY.REDUCTIONS END READU IREC FROM INVENTORY,IKEY THEN LOCATE(WHSE,IREC,INV$WAREHOUSE;FND;'AR') THEN IREC=IREC+ABS(QTY) LOCATE(YEAR,IREC,INV$ACTIVITY.YEARS,FND;WH;'DR') ELSE IREC=INSERT(IREC,INV$ACTIVITY.YEARS,FND,WH;YEAR) END END ELSE IREC=INSERT(IREC,INV$WAREHOUSE,FND;WHSE) IREC=INSERT(IREC,INV$QTY.INCREASES,FND;0) IREC=INSERT(IREC,INV$QTY.REDUCTIONS,FND;0) IREC=INSERT(IREC,INV$QTY.AVAILABLE,FND;0) IREC=INSERT(IREC,INV$QTY.BACKORDERED,FND;0) IREC=INSERT(IREC,INV$QTY.ON.ORDER,FND;"") IREC=INSERT(IREC,INV$EST.TIME.ARRIVAL,FND;"") IREC=INSERT(IREC,INV$PO.NUMBER,FND;"") IREC=INSERT(IREC,INV$ACTIVITY.YEARS,FND;"") IREC=INSERT(IREC,INV$LEAD.TIME,FND;"") IREC=INSERT(IREC,INV$REORDER.POINT,FND;0) IREC=INSERT(IREC,INV$SAFETY.STOCK,FND;0) IREC=INSERT(IREC,INV$EST.MONTHLY.USAGE,FND;0) IREC=INSERT(IREC,INV$PROJECTED.OS.DATE,FND;"") IREC=INSERT(IREC,INV$PRIMARY.LOCATION,FND;"") IREC=INSERT(IREC,INV$ALTERNATE.LOCATION1,FND;"") IREC=INSERT(IREC,INV$ALTERNATE.LOCATION2,FND;"") IREC=ABS(QTY) END PHYSICAL=IREC-IREC IF PHYSICAL < 0 THEN CRT @(0,22):CL:BEEP:"Warning! Physical quantity for ":ITEM:" is negative - ": *ANY=""; INPUT ANY CHANGED.FIELDS=CHANGED.FIELDS:"-P" END ELSE CHANGED.FIELDS=CHANGED.FIELDS:"P" END WRITE IREC ON INVENTORY,IKEY END RETURN * 5000 *---update INV.ACTIVITY HOLD.QTY=QTY ;*--save original value because we might change its sign BEGIN CASE CASE TYPE='SLS' QTY=QTY*MINUS ATTR=IA$SALES CASE TYPE='RTS' ATTR=IA$RETURNS CASE QTY > 0 ATTR=IA$INCREASES CASE QTY < 0 QTY=QTY*MINUS ATTR=IA$REDUCTIONS END CASE READU AREC FROM INV.ACTIVITY,AKEY THEN LOCATE(EFFPD,AREC,IA$PERIOD;WH;'DL') THEN AREC=AREC+QTY END ELSE AREC=INSERT(AREC,IA$PERIOD,WH;EFFPD) AREC=INSERT(AREC,IA$SALES,WH;0) AREC=INSERT(AREC,IA$RETURNS,WH;0) AREC=INSERT(AREC,IA$INCREASES,WH;0) AREC=INSERT(AREC,IA$REDUCTIONS,WH;0) AREC=AREC+QTY END END ELSE GOSUB 5100 ;*--determine beginning qty AREC=EFFPD AREC=BEGQTY AREC=0 AREC=0 AREC=0 AREC=0 AREC=AREC+QTY END WRITE AREC ON INV.ACTIVITY,AKEY QTY=HOLD.QTY ;*--restore qty variable to original value RETURN * 5100 *---determine warehouse beginning quantity for new year BEGQTY=0 DONE=FALSE CHECK.YEAR=YEAR LOOP UNTIL DONE DO KEY=CHECK.YEAR:"|":WHSE:"|":ITEM READ REC FROM INV.ACTIVITY,KEY THEN BEGQTY=REC-SUM(REC)+SUM(REC)+SUM(REC)-SUM(REC) DONE=TRUE END ELSE IF CHECK.YEAR > 1970 THEN CHECK.YEAR=CHECK.YEAR-1 END ELSE BEGQTY=0 DONE=TRUE END END REPEAT RETURN * 6000 *--inexhaustible supply update READU IREC FROM INVENTORY,ITEM THEN LOCATE(WHSE,IREC,INV$WAREHOUSE;FND;"AR") THEN QOH=IREC END ELSE QOH=0 END IF QTY > 0 THEN QOH=QOH-QTY END ELSE QOH=QOH+QTY END IF QOH < 0 THEN QTY.NEEDED=ABS(QOH) PASS.DATA=IMA.DATA PASS.DATA="INX" PASS.DATA=QTY.NEEDED PASS.DATA="Automatic Supply Increase" CALL CMSD.INV.MASTER(PASS.DATA) ;*--recursive call END END RETURN * 7000 *--assembled item update READU IREC FROM INVENTORY,ITEM THEN LOCATE(WHSE,IREC,INV$WAREHOUSE;FND;"AR") THEN QOH=IREC END ELSE QOH=0 END *---- * The following lines of code are designed to insure the correct * quantity is assembled. If action is ASSEMBLE then we are talking * about the manual process (from CMSD.ASSEMBLE.ITEMS) otherwise * we are simply doing an ASM transaction for the difference * between what is already available and what has been requested. *---- IF ACTION="ASSEMBLE" THEN QOH=0 END QOH=QOH-QTY IF QOH < 0 THEN QTY.NEEDED=ABS(QOH) MAX.AVAIL=999999999999 CCT=DCOUNT(IREC,VM) FOR C=1 TO CCT UNTIL MAX.AVAIL=0 CKEY=IREC CQTY=IREC READU CREC FROM INVENTORY,CKEY THEN IF CREC="Y" THEN MAX.AVAIL=0 IF CREC#"N" THEN LOCATE(WHSE,CREC,INV$WAREHOUSE;FND;"AR") THEN MAX.QTY=INT(CREC/CQTY) IF MAX.QTY < MAX.AVAIL THEN MAX.AVAIL=MAX.QTY END ELSE MAX.AVAIL=0 END END END ELSE MAX.AVAIL=0 END NEXT C IF ACTION="CHECK.AVAILABLE" THEN *--no updates will be performed FOR C=1 TO CCT *--release component items which have been locked RELEASE INVENTORY,IREC NEXT C IF MAX.AVAIL < QTY.NEEDED THEN REJECT=1 RETURN END IF MAX.AVAIL >= QTY.NEEDED THEN PASS.DATA=IMA.DATA PASS.DATA="ASM" PASS.DATA="Assembled into ":ITEM FOR C=1 TO CCT *---- * Loop through component items and call CMSD.INV.MASTER * to perform updates to inventory. As items remain locked * (preventing any updates) as a result of above evaluation, * and sufficient quantity has already been verified, * PASS.DATA will always return a "PASS" result back to this * program so IMA$RESULT does not need to be checked. * SPECIAL NOTE!!! This is a recursive call of a program * from within itself. Exercise EXTREME CAUTION when changing! *---- CITEM=IREC CQTY=IREC PASS.DATA=CITEM PASS.DATA=QTY.NEEDED*CQTY*MINUS CALL CMSD.INV.MASTER(PASS.DATA) ;*--recursive call NEXT C PASS.DATA=IMA.DATA PASS.DATA="ASM.ADD" PASS.DATA=QTY.NEEDED PASS.DATA="Assembled from Components" CALL CMSD.INV.MASTER(PASS.DATA) ;*--recursive call END ELSE FOR C=1 TO CCT *--release component items which have been locked RELEASE INVENTORY,IREC NEXT C REJECT=TRUE;*--cannot assemble enough to fulfill request REJECT.REASON=11 RETURN END END ELSE *---- * there is no need to assemble any items - sufficient * quantity is already available *---- END END RETURN * 8000 *--update PO related fields (PO.ADD & PO.DELETE) READU IREC FROM INVENTORY,ITEM THEN LOCATE(WHSE,IREC,INV$WAREHOUSE;FND;'AR') THEN LOCATE(TREF,IREC,INV$PO.NUMBER,FND;WH;'AR') THEN IREC=IREC+QTY IREC=TDATE *--verify ON ORDER is not zero else delete IF IREC=0 THEN IREC=DELETE(IREC,INV$PO.NUMBER,FND,WH) IREC=DELETE(IREC,INV$QTY.ON.ORDER,FND,WH) IREC=DELETE(IREC,INV$EST.TIME.ARRIVAL,FND,WH) END END ELSE IREC=INSERT(IREC,INV$PO.NUMBER,FND,WH;TREF) IREC=INSERT(IREC,INV$QTY.ON.ORDER,FND,WH;QTY) IREC=INSERT(IREC,INV$EST.TIME.ARRIVAL,FND,WH;TDATE) END END ELSE IREC=INSERT(IREC,INV$WAREHOUSE,FND;WHSE) IREC=INSERT(IREC,INV$QTY.INCREASES,FND;0) IREC=INSERT(IREC,INV$QTY.REDUCTIONS,FND;0) IREC=INSERT(IREC,INV$QTY.AVAILABLE,FND;0) IREC=INSERT(IREC,INV$QTY.BACKORDERED,FND;0) IREC=INSERT(IREC,INV$QTY.ON.ORDER,FND;QTY) IREC=INSERT(IREC,INV$EST.TIME.ARRIVAL,FND;TDATE) IREC=INSERT(IREC,INV$PO.NUMBER,FND;TREF) IREC=INSERT(IREC,INV$ACTIVITY.YEARS,FND;"") IREC=INSERT(IREC,INV$LEAD.TIME,FND;"") IREC=INSERT(IREC,INV$REORDER.POINT,FND;0) IREC=INSERT(IREC,INV$SAFETY.STOCK,FND;0) IREC=INSERT(IREC,INV$EST.MONTHLY.USAGE,FND;0) IREC=INSERT(IREC,INV$PROJECTED.OS.DATE,FND;"") IREC=INSERT(IREC,INV$PRIMARY.LOCATION,FND;"") IREC=INSERT(IREC,INV$ALTERNATE.LOCATION1,FND;"") IREC=INSERT(IREC,INV$ALTERNATE.LOCATION2,FND;"") END WRITE IREC ON INVENTORY,ITEM CHANGED.FIELDS=CHANGED.FIELDS:"O" END RETURN * 9000 *--update PO related fields (PO.RECEIVE) READU IREC FROM INVENTORY,ITEM THEN LOCATE(WHSE,IREC,INV$WAREHOUSE;FND;'AR') THEN LOCATE(TREF,IREC,INV$PO.NUMBER,FND;WH;'AR') THEN IREC=IREC+QTY * Verify ON ORDER is greater than zero else delete * NOTE: PO.RECEIVE of more than ordered quantity (overruns) * will leave nothing on order for specified PO. *---- IF IREC LE 0 THEN IREC=DELETE(IREC,INV$PO.NUMBER,FND,WH) IREC=DELETE(IREC,INV$QTY.ON.ORDER,FND,WH) IREC=DELETE(IREC,INV$EST.TIME.ARRIVAL,FND,WH) END WRITE IREC ON INVENTORY,ITEM CHANGED.FIELDS=CHANGED.FIELDS:"O" END ELSE *--nothing on order so nothing to do REJECT=TRUE END END ELSE *--nothing on order so nothing to do REJECT=TRUE END END RETURN * 10000 *--update INV.COST record COST=FIELD(CMNT,"|",2) SOURCE=FIELD(CMNT,"|",1) CKEY=WHSE:"|":ITEM CREC="" READU CREC FROM INV.COST,CKEY THEN IF CREC=COST THEN CREC=TDATE CREC=CREC+QTY CREC=SOURCE CREC=TREF END ELSE CREC=INSERT(CREC,IC$DATE.RECEIVED,1;TDATE) CREC=INSERT(CREC,IC$QTY.RECEIVED,1;QTY) CREC=INSERT(CREC,IC$UNIT.COST,1;COST) CREC=INSERT(CREC,IC$SOURCE,1;SOURCE) CREC=INSERT(CREC,IC$REFERENCE,1;TREF) END END ELSE CREC=TDATE CREC=QTY CREC=COST CREC=SOURCE CREC=TREF END WRITE CREC ON INV.COST,CKEY RETURN * 100000 *--return to calling program IF REJECT THEN IMA.DATA="FAIL" END ELSE IMA.DATA="PASS" END IMA.DATA=DATE() IMA.DATA=TIME() IMA.DATA=REJECT.REASON IMA.DATA=CHANGED.FIELDS WRITE IMA.DATA ON INV.JOURNAL,NEXT.JRNL RELEASE INVENTORY,IMA.DATA RETURN