Work Pick and Put in Code without using Warehouse App - arp6333/xplusplus GitHub Wiki

Execution order of the regular Warehouse app process with equivalent code (full code at bottom).

App Process would be:

  1. Login to Warehouse app (action:WHSWorkExecute in browser)
  2. Transloading
  3. Move and print label
  4. Enter Loc/LP and Item, click ok
  5. Enter batch, click ok
  6. Enter Qty / Weight

Relevant forms:

action:WHSWorkExecute - Open and use WH app in browser

WHSLicensePlateLabel - Created license plate labels

WHSWorkTable - Work and work lines

InventOnhandItem - Show available items / batches, filter by:

  • Location = Pick location
  • Warehouse = Warehouse to run in
  • Available physical = At least 1

image


WHSWorkExecuteDisplayMovementByTemplate

Instantiate code:

WHSTmpMovementWork tmpMovementWork;
InventDim          inventDim;
WhsWorkCreate      workCreate;
WhsWorkExecute     workExecute;
WHSWorkBuildId     workBuildId;
WHSWorkLine        workLine;

workExecute = WhsWorkExecute::construct();

Line 452 - if (complete): gets called after ok is hit the first time (before entering To info !!!)

  • fullLP = False
  • changingStatuses = True if invent status changes (ex going from 'BAG' into 'BOX')
  • isCWItem = false : No quarantineInventDim then
  • menuItemTable = 'Move and Print' (not needed for custom code)

Created / found InventDim from WH app

  • InventBatchId = Entered batch
  • InventLocationId = Warehouse user is running in
  • InventStatusId = To InventStatus
  • InventSiteId = Warehouse SiteId (ex 'GLOBAL')
  • LicensePlateId = '' blank!

Custom code:

inventDim.inventBatchId    = batch;
inventDim.inventLocationId = warehouse;
inventDim.wMSLocationId    = pickLocation;     // Use pick Location 
inventDim.InventStatusId   = toInventStatus;   // Use put InventStatus
inventDim.InventSiteId     = InventLocation::find(warehouse).inventSiteId;
inventDim                  = InventDim::findOrCreate(inventDim);

tmpMovementWork() from WH app

  • InventDimId = Same as created InventDim above
  • InventTransId = Null
  • ItemId = Item entered
  • Qty = Total quantity entered
  • UnitId = Unit of measure to use

Custom code:

tmpMovementWork.InventDimId = inventDim.InventDimId;
tmpMovementWork.ItemId      = itemId;
tmpMovementWork.Qty         = netWeight;
tmpMovementWork.UnitID      = unitId;

workCreate() from WH app

  • parmInventStatusId('BAG') - To status
  • parmCreatedBy(UserId) - Warehouse user
  • parmStartLocationId(FromLocation) - From location
    • parmWorkTemplateCode('Move and Print') - Not needed
    • parmLocDirHintCode('') - Blank, not needed
  • parmTargetLicensePlateId('') - Blank
    • parmCreateWorkInventTransWithTargetLP(fullLP (which is false here))
  • parmFromInventStatusId('BOX') - From status, only needed IF it is not the same as to status

Then createWork() is called.

createWork() is not called again from WHSWorkExecuteDisplayByTemplate.

Custom code:

ttsbegin;

workCreate = WHSWorkCreate::construct(tmpMovementWork);
workCreate.parmInventStatusId(toInventStatus);
workCreate.parmFromInventStatusId(fromInventStatus);
workCreate.parmCreatedBy(userWH);
workCreate.parmStartLocationId(pickLocation);
workCreate.parmCreateWorkInventTransWithTargetLP(false);

workBuildId = workCreate.createWork();

ttscommit;

Note: Any entered user / userId field should match the warehouse username, NOT the D365 user. This is needed to utilize the intermediary table that is used between the pick/put function. If getting 'Invalid location.' error it may be because it cannot find this intermediary table that must be the same name as the WH username. You may also need to login once if the user has just been created.


WHSWorkExecuteDisplay

Click ok to confirm pick:

  1. Line 9265, case (Pick): Second page ok click, before choosing put location
  2. workLine = workExecute.getFirstOpenLine(pass.lookup(#WorkId), userId); Add this to our code!
  3. Line 9501 executed
    1. assignSerial() returns false
  4. Line 9517 executed
  5. Line 9539, completePickStep(): Not applicable, only for UI changes

Pick custom code:

workLine     = WHSWorkTable::getFirstWorkLineByWorkBuildId(workBuildId, userWH);
licensePlate = this.generateLicensePlateId(itemId, unitId);

workLine = workExecute.pickNonLicensePlateCheckDigitQuantities(
	workLine.WorkId,
	workLine.LineNum,
	workLine.ItemId,
	workLine.QtyRemain,
	0,
	workLine.UnitId,
	userWH,
	inventDim,
	licensePlate,
	false
);

WHSWorkTable::addTargetLicensePlate(workLine.WorkId, licensePlate);

Changing put location

  1. Line 9940: Create work exception; NOT needed in my case since we don't care about override exceptions
    1. LineNum = 3
    2. WorkException = 'Location override'
    3. WMSLocationId = OLD location, not new one yet
  2. Line 9725: Get location id passing in new location
  3. Line 9782: Update work line location; then workLine.reread()

Change put location custom code:

WMSLocationId locationId = WMSLocation::whsGetLocationId(putLocation, warehouse);
if (!locationId)
{
	throw error("@WAX755");    // 'Invalid location.'
}
workExecute.updateWorkLineLocation(workLine.WorkId, 3, putLocation, userWH);    // 3 = workLine put line
workLine.reread();

Click ok to confirm put

  1. Line 9615 processPutWorkLine()
  2. Line 17390 executed
    1. sourceLP = '' blank
    2. targetLP = generated LP
    3. targetLPNotExist = true
    4. newLP = same as targetLP
    5. workFlowPut = 0
  3. Line 17548 processPutAwayToLocation()
  4. Line 17550 executed
    1. isDeferredPutContainerFeature = false
    2. isAllowUseOfDeferredPut = true
    3. Line 17568 executed
    4. putOperationParameters:
      1. handleByLP = false
      2. lineNum = 3
      3. putWMSLocationId = put location
      4. sourceLP = '' blank
      5. targetLP = generated LP
      6. userId = user
      7. workID = pulled from line
      8. workPutFlow = 0
    5. Line 10931 executed
      1. WHSContainerTable::determineContainerClose(workLine.WorkId);
      2. workExecute.putAwayToLocationConsiderDeferredPut(putOperationParameters, isAllowUseOfDeferredPut);

InventStatus changes

WHSWorkExecuteDisplay isInventoryStatusBeingChanged() - Method can check if true

Otherwise, just make sure:

inventDim.InventStatusId   = toInventStatus;
... // and:
workCreate.parmInventStatusId(toInventStatus);
workCreate.parmFromInventStatusId(fromInventStatus);

License plate label creation

Line 9671: LineNum = 2 (the label line (1 = pick, 3 = put))

Do any custom steps to the LP label here that need to be done before printing; it will be printed from labelBuild.buildLicensePlateLabels().

License plate label creation custom code:

WHSLicensePlateLabelBuild labelBuild = new WHSLicensePlateLabelBuild(workLine.WorkId, WHSWorkLine::find((workLine.WorkId), 2), '', userWH);
labelBuild.buildLicensePlateLabels();
workLine = workExecute.confirmCustomWork(workLine.WorkId, 2, userWH);

Full code

try
{
    // Get your work info here, including warehouse, pick location, put location, etc.

    WHSTmpMovementWork tmpMovementWork;
    InventDim          inventDim;
    WhsWorkCreate      workCreate;
    WhsWorkExecute     workExecute;
    WHSWorkBuildId     workBuildId;
    WHSWorkLine        workLine;

    workExecute = WhsWorkExecute::construct();

    // Find or create the InventDim
    inventDim.inventBatchId    = batch;
    inventDim.inventLocationId = warehouse;
    inventDim.wMSLocationId    = pickLocation;
    inventDim.InventStatusId   = toInventStatus;
    inventDim.InventSiteId     = InventLocation::find(warehouse).inventSiteId;
    inventDim                  = InventDim::findOrCreate(inventDim);

    // Create the work
    tmpMovementWork.clear();
    tmpMovementWork.InventDimId = inventDim.InventDimId;
    tmpMovementWork.ItemId      = itemId;
    tmpMovementWork.Qty         = netWeight;
    tmpMovementWork.UnitID      = unitId;

    ttsbegin;

    workCreate = WHSWorkCreate::construct(tmpMovementWork);
    workCreate.parmInventStatusId(toInventStatus);
    workCreate.parmFromInventStatusId(fromInventStatus);
    workCreate.parmCreatedBy(userWH);
    workCreate.parmStartLocationId(pickLocation);
    workCreate.parmCreateWorkInventTransWithTargetLP(false);

    workBuildId = workCreate.createWork();

    ttscommit;

    // Pick
    workLine     = WHSWorkTable::getFirstWorkLineByWorkBuildId(workBuildId, userWH);
    licensePlate = this.generateLicensePlateId(itemId, unitId);

    workLine = workExecute.pickNonLicensePlateCheckDigitQuantities(
        workLine.WorkId,
        workLine.LineNum,
        workLine.ItemId,
        workLine.QtyRemain,
        0,
        workLine.UnitId,
        userWH,
        inventDim,
        licensePlate,
        false
    );

    WHSWorkTable::addTargetLicensePlate(workLine.WorkId, licensePlate);

    // Set Put location
    WMSLocationId locationId = WMSLocation::whsGetLocationId(putLocation, warehouse);
    if (!locationId)
    {
        throw error("@WAX755");
    }
    workExecute.updateWorkLineLocation(workLine.WorkId, 3, putLocation, userWH);
    workLine.reread();

    // Put
    WHSContainerTable::determineContainerClose(workLine.WorkId);
    workLine = workExecute.putAwayToLocation(
        workLine.WorkId,
        3,
        putLocation,
        0,
        userWH,
        '',
        licensePlate,
        false
    );

    // Create the license plate label
    WHSLicensePlateLabelBuild labelBuild = new WHSLicensePlateLabelBuild(workLine.WorkId, WHSWorkLine::find((workLine.WorkId), 2), '', userWH);
    labelBuild.buildLicensePlateLabels();
    workLine = workExecute.confirmCustomWork(workLine.WorkId, 2, userWH);
}
catch
{
    // Get errors here
}
finally
{
    // Do any post processing here
}