Our customer is automating their invoice processing with a 3rd party program (AxTension). The invoices they receive from vendors often have only part of the purchase order number in them. Their current PO format is PO#######. Sometimes they just receive the numeric part, '1234567', sometimes the numeric part is missing the leading zeroes, '12345'. This kicks the PO numbers out as errors and the users would have to manually match them to the PO in the system.
I was asked to write logic that will "fix" the PO numbers that come in. First of all, if the PO number is blank, I just want to return (this avoids adding a po number for NON PO invoices):
if(_purchId == strMin())
{
return _purchId;
}
Then I had to find the number sequence format for the PurchId extended data type.
NumberSequenceReference Ref;
NumberSequenceDataType dataType;
NumberSequenceTable numSeq;
extendedTypeId poTypeId;
//Find the EDT id for your extended data type (mine is PurchId)
poTypeId = extendedTypeNum(PurchId);
select firstOnly RecId from dataType
where dataType.DatatypeId == poTypeId
join numbersequenceid from Ref
where Ref.numbersequencedatatype == datatype.recid|
join Format from numSeq
where numSeq.recid == Ref.numbersequenceid;
Once I have the numberSequenceTable record and the format field, I can use it to check the purchId that was passed into the system. I also did not want to show the user any errors so I store the length of the info log before and clear it after calling in to the numCheckFormat() method run a check on my format.
When you incorporate this into your class(es), you can have the user pass in the purchId and return the newPurchId you have fixed (public static PurchId validatePurchId(_purchId)). When you run it as a job, you can create the PurchId purchId variable and set it to the purchId you want to "fix."
int lines;
purchid purchid, newpurchid;
//Save current infolog spot
lines = infolog.line();
// Check to see if purchid matches format
if(!NumberSeq::numCheckFormat(purchID,numSeq))
{ // if check fails, fix purchid
//Cut any infolog messages that were created
infolog.cut(lines ? lines : 1);
//loop through the format
newpurchid = purchid;
for(i=1; i <= strLen(numseq.format); i++)
{
if(i > strLen(_purchId))
{ // if the purchid is longer than the format, we don't need to modify it (this only adds)
break;
}
f = subStr(numSeq.format,i,1);
p = substr(purchId,i,1);
if (f != '#')
{ // if we aren't looking for a number in the format
if(f != p)
{ // insert the character if it is in the format but not the purchid
if(strLen(purchId) < strLen(numSeq.Format))
{
//insert character into string
purchId = strIns(purchId, f, i);
}
//fix issue where readsoft reads the letter O as a numeric 0
else if (p == '0')
{ //Overwrite character in the string
purchId = strPoke(purchId, f, i);
}
} // END if f!=p
} // END if f!= '#'
} // END for
// After inserting the characters that exist in the format but not in the purchid, check the length
// if it's not long enough, we want to insert 0s before the existing numbers in the purchid
if(strLen(newpurchid) < strLen(numSeq.format))
{
zeroPos = strNFind(numSeq.Format,'#',strLen(numSeq.Format),-strLen(numSeq.Format));
newPurchId = strIns(newpurchid,strRep('0',strLen(numSeq.format)-strLen(newpurchId)),zeroPos+1);
}
You could also add logic that deletes unwanted characters from the purchid if it's not in the format, but we were assuming that wasn't going to happen. If it did happen, we would actually need user interaction to figure out if it matched with a PO in the system.
If you want an easy way to test this, you can create a dialog that allows you to enter your PurchId and your Format and ensure that the logic above will modify the PurchId the way you intend.
I added this to the job to give me a dialog:
Dialog dialog = new Dialog("Purchase order number");
DialogField dlgpurchid,dlgFormat;
dlgpurchid = dialog.addField(extendedTypeStr(str60),"Num to validate");
dlgFormat = dialog.addField(extendedTypeStr(NumberSequenceFormat));
dlgFormat.value("PO#######"); // Set my current known number sequence as a starting point
if(dialog.run())
{
purchid = dlgPurchId.value();
// code to select the num seq record from the table can go here
//After selecting the numsequencetable record, you would need to store the format from your dialog
numSeq.format = dlgFormat.value();
// code to fix the purchid can go here
}
This next section specifically references where to put the code in AxTension to adjust the PurchId. It has to be done on the header and the lines (as you can pass invoice number per line with AxTension).
1. Add method to AXTip_ImportPurchInvoices that will receive the purchId, fix it, and return the new purchId
2. Add code in method addInvoiceLine() where it calls the setField() for #Field_Line_PurchId. Replace it with this:
this.setField(#Field_Line_PurchId, this.YOURMETHOD(getFieldorDefaultValue(this.getField(#Field_Line_PurchId, ''), this.getField(#Field_PurchId, ''))));
3. Add code in method handlePurchInvoice(). After the if(importRunId), add this line of code:
this.setfield(#Field_PurchId,this.YOURMETHOD(this.getField(#Field_PurchId)));
4. Add code in class AXTip_ImportInvoices_ReadSoftOnline. This extends a class that extends the earlier class where you put your new method to fix the purchId. Add code in the analyzeFile() method.
Set default Id with your new logic.
defaultPurchId = this.YOURMETHOD(this.getfield(#Field_PurchId, ''));
5. In the readsoftonline class in #4, add code in the setHeaderFields() method:
change the this.setField() for the #Field_PurchId to call your new method instead
this.setfield(#Field_PurchId, this.YOURMETHOD(this.marshalStr(documentData.get_PurchId(), identifierStr(PurchId))));
Hope this helps!
-Amber