def update_invoice_lines(self): # The incoming invoice lines should look like: ''' [{ 'code': 'COPPER', 'quantity': 1 'traded': true // or not present. }, ...] ''' # coerce the incoming invoice lines: incoming_lines = [ IL(line, updater=self) for line in self.blob['invoice_lines'] ] # If the IL constructor put any errors in, stop now. if self.errors: return # Next get every existing invoice line. self.existing_lines = list(self.agreement.invoice_lines.all()) self.unclaimed_lines = list( self.existing_lines ) # Unclaim all existing lines. We may reclaim them soon. # this is the list of lines that will be on the agreement at the end: self.final_lines = [] for il in list(incoming_lines): if not il.price: incoming_lines.remove(il) self.messages.append( '%s removed from the agreement because it is not available.' % il.code) continue available = getattr(il.price, 'available_mask', None) if available is None: available = il.price.available if not available: incoming_lines.remove(il) self.messages.append( '%s removed from the agreement because it is no longer available.' % il.code) continue # First, do every line that came in from the system NOT traded. # Invoice Lines for these should all be TOP. # (This includes package, monitoring, alacarte, but not children, mandatory services...) for il in incoming_lines: if not il.line_type == 'TOP': continue # il is a fakey line. line = self.reclaim_line(code=il.code, line_type='TOP') if not line: line = InvoiceLine(agreement=self.agreement) line.update_top(product=il.product, quantity=il.quantity, price=il.price, pricedate=self.agreement.pricedate) self.final_lines.append(line) # Now do it again for trade lines. for il in incoming_lines: if not il.line_type == 'TRADE': continue line = self.reclaim_line(code=il.code, line_type='TRADE') if not line: line = InvoiceLine(agreement=self.agreement) line.update_trade(product=il.product, quantity=il.quantity, price=il.price, pricedate=self.agreement.pricedate) self.final_lines.append(line) # Save any lines in final_lines because they'll need pks for their children. for line in self.final_lines: line.save() print "Final lines BEFORE CHILD SYNC:" for line in self.final_lines: print "{}, {}, {}".format(line.code, line.quantity, line.traded) # loop through, adding mandatory items and syncing children until no changes are made. loops = 0 self.sync_all_children() while True: # Next, we need to process mandatory items. changed = self.add_mandatory_items() # Then, sync children again. changed = self.sync_all_children() or changed if not changed: break loops += 1 if loops >= 10: self.errors.append( "Probably an infinite loop in mandatories/children. Needs fixin." ) break # Next reclaim/create a permit line if needed. self.add_permit_lines() self.sanity_check() print "Final lines:" for line in self.final_lines: print "{}, {}, {}".format(line.code, line.quantity, line.traded) # Finally, any lines that are in existing_lines but not in final_lines should be deleted. for orphan in self.existing_lines: if orphan in self.final_lines: continue orphan.delete()
def update_invoice_lines(self): # The incoming invoice lines should look like: ''' [{ 'code': 'COPPER', 'quantity': 1 'traded': true // or not present. }, ...] ''' # coerce the incoming invoice lines: incoming_lines = [IL(line, updater=self) for line in self.blob['invoice_lines']] # If the IL constructor put any errors in, stop now. if self.errors: return # Next get every existing invoice line. self.existing_lines = list(self.agreement.invoice_lines.all()) self.unclaimed_lines = list(self.existing_lines) # Unclaim all existing lines. We may reclaim them soon. # this is the list of lines that will be on the agreement at the end: self.final_lines = [] for il in list(incoming_lines): if not il.price: incoming_lines.remove(il) self.messages.append('%s removed from the agreement because it is not available.' % il.code) continue available = getattr(il.price, 'available_mask', None) if available is None: available = il.price.available if not available: incoming_lines.remove(il) self.messages.append('%s removed from the agreement because it is no longer available.' % il.code) continue # First, do every line that came in from the system NOT traded. # Invoice Lines for these should all be TOP. # (This includes package, monitoring, alacarte, but not children, mandatory services...) for il in incoming_lines: if not il.line_type == 'TOP': continue # il is a fakey line. line = self.reclaim_line(code=il.code, line_type='TOP') if not line: line = InvoiceLine(agreement=self.agreement) line.update_top(product=il.product, quantity=il.quantity, price=il.price, pricedate=self.agreement.pricedate) self.final_lines.append(line) # Now do it again for trade lines. for il in incoming_lines: if not il.line_type == 'TRADE': continue line = self.reclaim_line(code=il.code, line_type='TRADE') if not line: line = InvoiceLine(agreement=self.agreement) line.update_trade(product=il.product, quantity=il.quantity, price=il.price, pricedate=self.agreement.pricedate) self.final_lines.append(line) # Save any lines in final_lines because they'll need pks for their children. for line in self.final_lines: line.save() print "Final lines BEFORE CHILD SYNC:" for line in self.final_lines: print "{}, {}, {}".format(line.code, line.quantity, line.traded) # loop through, adding mandatory items and syncing children until no changes are made. loops = 0 self.sync_all_children() while True: # Next, we need to process mandatory items. changed = self.add_mandatory_items() # Then, sync children again. changed = self.sync_all_children() or changed if not changed: break loops += 1 if loops >= 10: self.errors.append("Probably an infinite loop in mandatories/children. Needs fixin.") break # Next reclaim/create a permit line if needed. self.add_permit_lines() self.sanity_check() print "Final lines:" for line in self.final_lines: print "{}, {}, {}".format(line.code, line.quantity, line.traded) # Finally, any lines that are in existing_lines but not in final_lines should be deleted. for orphan in self.existing_lines: if orphan in self.final_lines: continue orphan.delete()