Update Custom Field from within a Method of a Class

Questions about and code samples for custom order rules and validation within Select.
Post Reply
B_Hinote
Posts: 40
Joined: Tue Jan 08, 2019 7:20 pm

Update Custom Field from within a Method of a Class

Post by B_Hinote » Fri Jul 12, 2019 1:18 am

Is it possible to update a custom field from within a Static Method of a Class?

I was looking at an example Rule that set the Invoice Number based on the Order Number and the str(args.Context.Position). The only issue with this is that the Invoice Number will change if an invoice is deleted causing the position to change.

One possibility is to condition the rule to return before changing the Invoice Number if the Number is already set.

Code: Select all

def Invoice_Number_Value(args):
	# Run Default Rules ifn Invoice Number already set.
	if args.Context.Number is not None:
		args.RunDefaultRule()
		return
	
	# Set the Invoice Number based on the Order Nubmer and Position of the invoice.
	args.Value = args.Context.Root.Number + '-' + str(args.Context.Position)
However, this too will be a problem if the user for any reason overwrites the invoice number and then F2s the field. This will cause the invoice number to be updated based on the new position.

What I was hoping we might be able to do is as follows:
1. Add a Hidden Custom Field to the Order Context that will be used to store the last Sequence Number Assigned for each invoice. (Each time a new invoice is created this value will be increased by one.) "Order.LastInvoiceSeq##"
2. Also, add a Custom Field to the Invoice Context that will be used to store the Sequence Number generated and assigned to each Invoice created. A rule will be created for the Invoice Level Custom Field, that hopefully can call a Static Method defined in a Class, to first increment the Order.LastInvoiceSeq## by one, when the Invoice Level field is empty and then store this value in the Invoice Level Custom Field. "Order.Invoices.InvoiceSeq##" Because the rule would be conditioned to not run when a value is assigned, it would remain the same value no matter what position it became.
3. Then the rule used to assign the Invoice Number would be designed to use the "Order.Invoices.InvoiceSeq##" instead of the Invoice Position.

In theory, this should provide unique Invoice Numbering that does not reset based on the position of the invoice and would retain the sequence number assigned to it even if the user messes with the invoice number field.

I am just not sure how to wrap the change of the Overall Order.LastInvoiceSeq## field up in a Class that is only called when the Invoice Level Custom Field is Empty.

Code: Select all

def Invoice_Number_Value(args):
	# Run Default Rules if Invoice Number already set.
	if args.Context.Number is not None:
		args.RunDefaultRule()
		return
	
	order = args.Context.Root
	
	# Set the Invoice Number using Order Nubmer and Next Invoice Sequence
	args.Value = args.Context.Root.Number + '-' + IOrderItem.GetProperty(order, 'LastInvoiceSeq##')

def Invoice_InvoiceSeq_Value(args):
	""" Set InvoiceSeq## Custom Field based on Custom Field LastInvoiceSeq## """
	args.Value = ClassName.GetNextInvoiceNubmer() # This would be the class and method the returns the value from the Master Seqence.


# Redefine Custom Field Rule names
Invoice_InvoiceSeq_Value.__name__ = "Order_Invoice_InvoiceSeq##_Value"

Thank you for any information you may be able to provide.

BobRichards
Posts: 1006
Joined: Wed Jan 15, 2014 3:50 pm
Location: Raleigh, NC
Contact:

Re: Update Custom Field from within a Method of a Class

Post by BobRichards » Wed Jul 17, 2019 1:50 pm

There is an easier way to generate a value and have it be fixed for the life of the order. Using tags, you can store information in the order in a way that doesn't require custom properties. You can also store the initial seed value and increment it as more items are added to generate unique monotonically increasing labels. Additionally, tags cannot be altered by users. The special quality of a tag to leverage is if you call GetTag() and the tag name doesn't exist, it will return None.

In the invoice number value aspect, I get the tag named 'TheNumber'. If I get a non-zero length string back, I know that it is the value I previously set and restore the value. However, if the value is not set, I call GetNextIndex() to get the next value in the series and stick that to the end of template for the invoice numbers.

Code: Select all

from System import *
from SoftPro.ClientModel import *
from SoftPro.OrderTracking.Client import *
from SoftPro.OrderTracking.Client.Orders import *

def Invoice_Number_Value(args):
	value = IOrderItem.GetTag(args.Context, 'TheNumber')
	if not value:
		# Number never assigned. Get next index and add it to invoice name.
		value = 'Invoice #' + GetNextIndex(args.Context.Root)
		IOrderItem.SetTag(args.Context, 'TheNumber', value)	
		
	args.Value = value
I keep the value I use to assign index values at the top level of the order (the root) so I can get to it easily. The tag should have a unique name so no other CORs interfere with it..

Code: Select all

# Get last index returned, increment it then return it as string. 
#   If never called before, set the first value returned to "1".
def GetNextIndex(order):
	s = IOrderItem.GetTag(order, '536e87242b4a!!')
	if not s:
		# Never called before.  Set the initial value.
		index = 0
	else:
		index = int(s)
	
	# Create next index and save it for future calls.
	s = str(index + 1)
	IOrderItem.SetTag(order, '536e87242b4a!!', s)
	
	return s
Bob Richards, Software Developer, SoftPro

B_Hinote
Posts: 40
Joined: Tue Jan 08, 2019 7:20 pm

Re: Update Custom Field from within a Method of a Class

Post by B_Hinote » Wed Jul 17, 2019 9:07 pm

This is perfect. It works exactly the way I was hoping it would.

I greatly appreciate your help and willingness to show me a better way.

Thank you

Post Reply