Auto-print labels from a BPM
Users forget to print labels, or print them twice. The Auto Print widget in a BPM prints a label at the moment something happens, such as a pack being closed, without anyone opening the report screen. BarTender labels work with the same widget as SSRS reports; only the report type differs.
For the widget itself and how its parameters work, see Send email and auto-print from a BPM. This page covers the label-specific parts.
Example: shipping labels when a pack is closed
Section titled “Example: shipping labels when a pack is closed”- Create a Standard data directive on the
ShipHeadtable. Standard means the label is only produced once the save has been committed. - Add a Condition: the
ShipStatusfield of the changed row has been changed from any to the closed status (CLOSEDin the source setup; check the value your release uses). Testing for the change, not the state, stops a reprint every time someone edits the closed pack. - On True, add Auto Print and choose the report:
- Report:
GenShip(Generic Shipping), with Report Type set to Bartender Labels. - Style: your BarTender style for this label.
- Report:
- Set the report options:
- Run Schedule: Immediate, or Queued if you’d rather the task agent pick it up in turn.
- Print Action: Auto Print.
- Printer: a server printer whose name matches a printer on the BarTender server, or Use Default Printer.
- Print Quantity: a constant, usually
1. Label quantities are normally driven by the data or the template.
- On Report Parameters, set
PackNumto the table fieldShipHead.PackNumfrom the directive’s row. Leave the other parameters at their defaults. - Enable the directive and close a test pack. A
.btfile should appear in the style’s output folder within a few seconds.
Staging values the report doesn’t have
Section titled “Staging values the report doesn’t have”Sometimes a label needs values that exist only at print time: the quantity per carton, or how many labels to print, typed by the user when they print. One way to get them onto the label is to stage them in a UD table, keyed so the report data can join to them.
The shape of the pattern:
- Collect the values, for example in a BPM data form, and hold them in
callContextBpmData(see Pass data from pre- to post-processing). - In a directive that runs when the label report is submitted, write one row per print request to a
UD table such as
UD05, keyed by the pack number. - Add the UD table to a copy of the report data definition, joined on that key, so its columns appear
in the
.btfile. - Clean up old staging rows on a schedule.
The staging write, in a pre-processing directive on the packing slip report’s submit method (its
tableset carries the PackingSlipParam row), so the row exists before the report task starts:
int packNum = ds.PackingSlipParam[0].PackNum;
var stage = new Ice.Tables.UD05{ Company = Session.CompanyID, Key1 = packNum.ToString(), Key2 = Guid.NewGuid().ToString(), // one row per print request Key3 = "", Key4 = "", Key5 = "", Date01 = DateTime.Now // lets the cleanup find old rows};
// XX_ columns added to UD05 in Extended UD Table Maintenancestage.XX_QtyPerCarton_c = callContextBpmData.Number01;stage.XX_LabelCount_c = Convert.ToInt32(callContextBpmData.Number02);
Db.UD05.Insert(stage);Db.Validate();And a cleanup, as an Epicor Function run on a schedule. It deletes only rows older than an hour, so it never removes a row for a label that is still in the queue:
var cutoff = DateTime.Now.AddHours(-1);
var oldRows = Db.UD05 .Where(r => r.Company == Session.CompanyID && r.Date01 < cutoff) .ToList();
foreach (var row in oldRows){ Db.UD05.Delete(row);}
Db.Validate();The function library needs UD05 added as a table reference with write access for this to compile.
How it works
Section titled “How it works”- Every row has a unique key (
Key2is a GUID), so two people printing the same pack at once don’t collide or overwrite each other. Db.Validate()writes the inserted or deleted rows to the database there and then, rather than leaving them to whatever save happens next.- If the table is shared with other uses, put a fixed value in a spare key (for example
Key3 = "LABEL") and filter the cleanup on it too.