def extract(self, picking): """ Takes a stock.picking browse_record and extracts the appropriate data into self.data @param browse_record(stock.picking) picking: the stock picking browse record object """ self.data = OrderedDict([ ('InboundShipmentCreate', OrderedDict([ ('InboundShipmentHeader', OrderedDict([ ('ClientOfOrder', 'FW9'), ('ShipmentReference', picking.name), ('Warehouse', 'GAR'), ('OrderType', 'PO'), ('SupplierId', picking.partner_id.name), ('Remark', picking.note), ('DocumentFileNumber', picking.origin), ('RegistrationDate', parse_date(picking.date).isoformat()), ('ExpectedArrivalTime', parse_date(picking.min_date).isoformat()), ('Addresses', OrderedDict([ ('Address', [ OrderedDict([ ('Type', 'ShipFrom'), ('PartnerId', picking.partner_id.name), ('Name', picking.partner_id.name), ('City', picking.partner_id.city), ('CityZip', picking.partner_id.zip), ('District', picking.partner_id.country_id.code), ])]), ])), ])), ('InboundShipmentLines', OrderedDict([ ('InboundShipmentLine', []) ])), ])), ]) # iterate on move lines and use the template to create a data node that represents the PO line for move in picking.move_lines: # construct picking line dict picking_line = OrderedDict([ ('LineReference', move.id), ('Item', OrderedDict([ ('ItemAttributes', OrderedDict([ ('Client', 'FW9'), ('Item', move.product_id.ean13), ])), ])), ('ExpectedQty', move.product_qty), ]) # insert data into self.data and increment picking line count self.data['InboundShipmentCreate']['InboundShipmentLines']['InboundShipmentLine'].append(picking_line) return self
def _extract_data(self, ret): """ Extract data from a return node sent by LX1. picking_name and return_code are required. """ assert all([field in ret for field in ['NUM_FACTURE_BL', 'CODE_MOTIF_RETOUR']]), \ _('A return has been skipped because it was missing a required field: %s' % ret) ret_data = {} ret_data['picking_name'] = ret['NUM_FACTURE_BL'] ret_data['return_code'] = ret['CODE_MOTIF_RETOUR'] ret_data['return_reason'] = self.safe_get(self.return_code_mapping, ret_data['return_code']) \ or _('Code not recognised: ') + ret_data['return_code'] ret_data['return_date'] = parse_date(self.safe_get(ret, 'DATE_RETOUR')) ret_data['product_code'] = self.safe_get(ret, 'CODE_ART') ret_data['quantity_sent'] = self.safe_get(ret, 'QTEEXP') ret_data['quantity_returned'] = self.safe_get(ret, 'QTERET') return ret_data
def _extract_data(self, ret): """ Extract data from a return node sent by LX1. picking_name and return_code are required. """ assert all([field in ret for field in ["NUM_FACTURE_BL", "CODE_MOTIF_RETOUR"]]), _( "A return has been skipped because it was missing a required field: %s" % ret ) ret_data = {} ret_data["picking_name"] = ret["NUM_FACTURE_BL"] ret_data["return_code"] = ret["CODE_MOTIF_RETOUR"] ret_data["return_reason"] = ( self.safe_get(self.return_code_mapping, ret_data["return_code"]) or _("Code not recognised: ") + ret_data["return_code"] ) ret_data["return_date"] = parse_date(self.safe_get(ret, "DATE_RETOUR")) ret_data["product_code"] = self.safe_get(ret, "CODE_ART") ret_data["quantity_sent"] = self.safe_get(ret, "QTEEXP") ret_data["quantity_returned"] = self.safe_get(ret, "QTERET") return ret_data
def extract(self, picking_out): """ Takes a stock.picking_out.out browse_record and extracts the appropriate data into self.data @param picking_out: browse_record(stock.picking.out) """ pool = picking_out.pool cr = picking_out._cr uid = 1 carrier_obj = pool['delivery.carrier'] product_obj = pool['product.product'] picking_obj = pool['stock.picking'] picking = picking_obj.browse(cr, 1, picking_out.id) shipping_partner = picking_out.sale_id.partner_shipping_id invoice_partner = picking_out.sale_id.partner_invoice_id carrier = None carrier_name = None carrier_move_ids = [] # Get carrier information from the sale_id if picking_out.sale_id.carrier_id: carrier = picking_out.sale_id.carrier_id carrier_name = carrier.lx_ref # Delivery methods can be added as move lines, so find all move lines whose products # are the delivery products of a delivery method and save IDS and lx ref for later product_ids = [ move.product_id.id for move in picking_out.move_lines if move.product_id ] # all products on SO carrier_map = product_obj.is_delivery_method( cr, uid, product_ids ) # dict of product ids with delivery method ids as values carrier_product_ids = [ product_id for product_id, carrier_ids in carrier_map.iteritems() if carrier_ids ] # IDS of products used in delivery orders carrier_move_ids = [ move.id for move in picking.move_lines if move.product_id and move.product_id.id in carrier_product_ids ] # IDS of moves for delivery order products # Set carrier and carrier_name if not already set carrier_move_ids_temp = copy(carrier_move_ids) while not carrier_name and len(carrier_move_ids_temp) > 0: carrier_move_id = carrier_move_ids_temp.pop() for move in picking_out.move_lines: if move.id in carrier_move_ids: carrier = carrier_obj.browse( cr, uid, carrier_map[move.product_id.id][0]) carrier_name = carrier.lx_ref or '' # Carrier LX Ref is required if carrier and not carrier_name: raise osv.except_osv( _("Missing Carrier LX Ref"), _("The delivery carrier '%s' does not have an LX Reference. Please provide one by going to Warehouse > Delivery Methods" ) % carrier.name) if not carrier and not carrier_name: carrier_name = 'DHL_FW9' # generate invoice reports if not all([ invoice.state in ['open', 'paid'] for invoice in picking.sale_id.invoice_ids ]): raise osv.except_osv( _('Invoice is Draft'), _('Picking "%s" has an invoice in draft state. All invoices belonging to this picking must be validated before processing.' ) % picking.name) self.add_attachments( pool, cr, uid, 'account.invoice', [invoice.id for invoice in picking.sale_id.invoice_ids], 'account.report_invoice', picking.name + '_invoice', 'InvoiceDoc') # generate delivery slip self.add_attachments(pool, cr, uid, 'stock.picking.out', [picking.id], 'stock.report_picking', picking.name + '_delivery', 'ShptDoc') # extract browse_record into self.data self.data = OrderedDict([ ('DeliveryOrderCreate', OrderedDict([ ('DeliveryOrderHeader', OrderedDict([ ('ClientOfOrder', 'FW9'), ('OrderReference', picking_out.sale_id.name), ('Warehouse', 'GAR'), ('CustomerId', invoice_partner.id), ('ShippingType', carrier_name), ('ExpectedDeliveryDate', parse_date(picking_out.min_date).isoformat()), ('Remark', picking_out.note or ''), ('DocumentFileNumber', picking_out.name), ('Addresses', OrderedDict([ ('Address', [ OrderedDict([ ('Type', 'ShipTo'), ('PartnerId', shipping_partner.name), ('Name', shipping_partner.name), ('Street', shipping_partner.street or ''), ('City', shipping_partner.city or ''), ('CityZip', shipping_partner.zip), ('CountryCode', shipping_partner.country_id.code), ]), OrderedDict([ ('Type', 'BillTo'), ('PartnerId', invoice_partner.name), ('Name', invoice_partner.name), ('Street', invoice_partner.street or ''), ('City', invoice_partner.city or ''), ('CityZip', invoice_partner.zip), ('CountryCode', invoice_partner.country_id.code), ]) ]), ])), ('Attributes', OrderedDict([ ('Attribute', []), ])), ])), ('DeliveryOrderLines', OrderedDict([('DeliveryOrderLine', []) ])), ])), ]) # fill attachments for content, name, extension, type in self._attachments: attachment = OrderedDict([ ('AttributeType', type), ('AttributeValue', '%s.%s' % (name, extension)), ]) self.data['DeliveryOrderCreate']['DeliveryOrderHeader'][ 'Attributes']['Attribute'].append(attachment) for move in picking_out.move_lines: # skip lines that are cancelled, missing product_id, or product_id is delivery method or service if move.state == 'cancel' \ or not move.product_id \ or move.id in carrier_move_ids \ or move.product_id.type == 'service': continue # prepare line information line = OrderedDict([ ('LineReference', move.id), ('Item', OrderedDict([ ('ItemAttributes', OrderedDict([ ('Client', 'FW9'), ('Item', move.product_id.ean13), ])), ('SerialCaptureFlag', 'No'), ('QuantityRoundUpRule', 'EXACT'), ('InventorizedItemFlag', 'Yes'), ])), ('OrderQty', move.product_qty), ]) # add line into list of lines and increment line counter self.data['DeliveryOrderCreate']['DeliveryOrderLines'][ 'DeliveryOrderLine'].append(line) return self
def _process_picking(self, pool, cr, picking_name, picking_lines_original): """ Executes the reception wizard for an IN or the delivery wizard for an out with data from self.data received from LX1 @param pool: OpenERP object pool @param cursor cr: OpenERP database cursor @param str picking_name: Name of the picking to be processed @param list picking_lines: A list of picking move data. Refer to self._extract_to_process """ # validate params and find picking if not picking_lines_original: return assert picking_name, _("A picking was received from LX1 without a name, so we can't process it") picking_id = self._find_picking(pool, cr, picking_name) assert picking_id, _("No picking found with name %s" % picking_name) picking = pool.get('stock.picking').browse(cr, 1, picking_id) assert picking.state != 'done', _("Picking '%s' (%d) has already been closed" % (picking_name, picking_id)) # create working copy of picking_lines_original in case original is needed intact higher in the stack picking_lines = deepcopy(picking_lines_original) # set move_date to first not falsey date in picking_lines, or now() move_date = datetime.now() for picking_line in picking_lines: if picking_line['date']: move_date = parse_date(picking_line['date']) break # create a wizard record for this picking context = { 'active_model': 'stock.picking.%s' % picking_lines[0]['move_type'], 'active_ids': [picking_id], 'active_id': picking_id, } wizard_obj = pool.get('stock.partial.picking') wizard_line_obj = pool.get('stock.partial.picking.line') wizard_id = wizard_obj.create(cr, 1, {'date': move_date}, context=context) wizard = wizard_obj.browse(cr, 1, wizard_id) # reset quantities received to zero wizard_line_obj.write(cr, 1, [move.id for move in wizard.move_ids], {'quantity': 0}) # Consider: Picking with two lines same product x 1 and 5. Receive 5 on 1 and 1 on 5, 4 left over to deliver! # Sort wizard moves and picking lines to have lowest quantity first so they are processed in that order. wizard.move_ids.sort(key=lambda move: move.move_id.product_qty) picking_lines.sort(key=lambda line: line['quantity'], reverse=True) # reverse order because they are reverse iterated # Iterate on wizard move lines setting quantity received to that in picking lines, or 0 for move in wizard.move_ids: move_product_reference = move.product_id.x_new_ref move_quantity_ordered = move.move_id.product_qty remainder = None # process picking lines in reverse order, removing them at the end for picking_line_index in reversed(xrange(len(picking_lines))): picking_line = picking_lines[picking_line_index] # If picking line name matches move product x_new_ref, process picking_line quantity if move_product_reference == picking_line['name']: # If received qty > ordered qty and we have second picking line for same product, # set received qty to full and add remainder to next picking line if picking_line['quantity'] > move_quantity_ordered \ and len([line for line in picking_lines if line['name'] == move_product_reference]) > 1: # Set move qty as full. Save remainder for next line wizard_line_obj.write(cr, 1, move.id, {'quantity': move_quantity_ordered}) remainder = picking_line['quantity'] - move_quantity_ordered else: # just write quantity on line wizard_line_obj.write(cr, 1, move.id, {'quantity': picking_line['quantity']}) # picking line processed so delete it from the list del picking_lines[picking_line_index] # add remainder to next line if remainder != None: [line for line in picking_lines if line['name'] == move_product_reference][0]['quantity'] += remainder remainder = None # break when picking line is found for move, to avoid processing multiple picking lines on a single move break # Process receipt wizard_obj.do_partial(cr, 1, [wizard_id])
def extract(self, picking): """ Takes a stock.picking browse_record and extracts the appropriate data into self.data @param browse_record(stock.picking) picking: the stock picking browse record object """ self.data = OrderedDict([ ('InboundShipmentCreate', OrderedDict([ ('InboundShipmentHeader', OrderedDict([ ('ClientOfOrder', 'FW9'), ('ShipmentReference', picking.name), ('Warehouse', 'GAR'), ('OrderType', 'PO'), ('SupplierId', picking.partner_id.name), ('Remark', picking.note), ('DocumentFileNumber', picking.origin), ('RegistrationDate', parse_date(picking.date).isoformat()), ('ExpectedArrivalTime', parse_date(picking.min_date).isoformat()), ('Addresses', OrderedDict([ ('Address', [ OrderedDict([ ('Type', 'ShipFrom'), ('PartnerId', picking.partner_id.name), ('Name', picking.partner_id.name), ('City', picking.partner_id.city), ('CityZip', picking.partner_id.zip), ('District', picking.partner_id.country_id.code), ]) ]), ])), ])), ('InboundShipmentLines', OrderedDict([('InboundShipmentLine', [])])), ])), ]) # iterate on move lines and use the template to create a data node that represents the PO line for move in picking.move_lines: # construct picking line dict picking_line = OrderedDict([ ('LineReference', move.id), ('Item', OrderedDict([ ('ItemAttributes', OrderedDict([ ('Client', 'FW9'), ('Item', move.product_id.ean13), ])), ])), ('ExpectedQty', move.product_qty), ]) # insert data into self.data and increment picking line count self.data['InboundShipmentCreate']['InboundShipmentLines'][ 'InboundShipmentLine'].append(picking_line) return self
def extract(self, picking_out): """ Takes a stock.picking_out.out browse_record and extracts the appropriate data into self.data @param picking_out: browse_record(stock.picking.out) """ pool = picking_out.pool cr = picking_out._cr uid = 1 carrier_obj = pool['delivery.carrier'] product_obj = pool['product.product'] picking_obj = pool['stock.picking'] picking = picking_obj.browse(cr, 1, picking_out.id) shipping_partner = picking_out.sale_id.partner_shipping_id invoice_partner = picking_out.sale_id.partner_invoice_id carrier = None carrier_name = None carrier_move_ids = [] # Get carrier information from the sale_id if picking_out.sale_id.carrier_id: carrier = picking_out.sale_id.carrier_id carrier_name = carrier.lx_ref # Delivery methods can be added as move lines, so find all move lines whose products # are the delivery products of a delivery method and save IDS and lx ref for later product_ids = [move.product_id.id for move in picking_out.move_lines if move.product_id] # all products on SO carrier_map = product_obj.is_delivery_method(cr, uid, product_ids) # dict of product ids with delivery method ids as values carrier_product_ids = [product_id for product_id, carrier_ids in carrier_map.iteritems() if carrier_ids] # IDS of products used in delivery orders carrier_move_ids = [move.id for move in picking.move_lines if move.product_id and move.product_id.id in carrier_product_ids] # IDS of moves for delivery order products # Set carrier and carrier_name if not already set carrier_move_ids_temp = copy(carrier_move_ids) while not carrier_name and len(carrier_move_ids_temp) > 0: carrier_move_id = carrier_move_ids_temp.pop() for move in picking_out.move_lines: if move.id in carrier_move_ids: carrier = carrier_obj.browse(cr, uid, carrier_map[move.product_id.id][0]) carrier_name = carrier.lx_ref or '' # Carrier LX Ref is required if carrier and not carrier_name: raise osv.except_osv(_("Missing Carrier LX Ref"), _("The delivery carrier '%s' does not have an LX Reference. Please provide one by going to Warehouse > Delivery Methods") % carrier.name) if not carrier and not carrier_name: carrier_name = 'DHL_FW9' # generate invoice reports if not all([invoice.state in ['open', 'paid'] for invoice in picking.sale_id.invoice_ids]): raise osv.except_osv(_('Invoice is Draft'), _('Picking "%s" has an invoice in draft state. All invoices belonging to this picking must be validated before processing.') % picking.name) self.add_attachments(pool, cr, uid, 'account.invoice', [invoice.id for invoice in picking.sale_id.invoice_ids], 'account.report_invoice', picking.name + '_invoice', 'InvoiceDoc') # generate delivery slip self.add_attachments(pool, cr, uid, 'stock.picking.out', [picking.id], 'stock.report_picking', picking.name + '_delivery', 'ShptDoc') # extract browse_record into self.data self.data = OrderedDict([ ('DeliveryOrderCreate', OrderedDict([ ('DeliveryOrderHeader', OrderedDict([ ('ClientOfOrder', 'FW9'), ('OrderReference', picking_out.sale_id.name), ('Warehouse', 'GAR'), ('CustomerId', invoice_partner.id), ('ShippingType', carrier_name), ('ExpectedDeliveryDate', parse_date(picking_out.min_date).isoformat()), ('Remark', picking_out.note or ''), ('DocumentFileNumber', picking_out.name), ('Addresses', OrderedDict([ ('Address', [OrderedDict([ ('Type', 'ShipTo'), ('PartnerId', shipping_partner.name), ('Name', shipping_partner.name), ('Street', shipping_partner.street or ''), ('City', shipping_partner.city or ''), ('CityZip', shipping_partner.zip), ('CountryCode', shipping_partner.country_id.code), ]), OrderedDict([ ('Type', 'BillTo'), ('PartnerId', invoice_partner.name), ('Name', invoice_partner.name), ('Street', invoice_partner.street or ''), ('City', invoice_partner.city or ''), ('CityZip', invoice_partner.zip), ('CountryCode', invoice_partner.country_id.code), ])]), ])), ('Attributes', OrderedDict([ ('Attribute', []), ])), ])), ('DeliveryOrderLines', OrderedDict([ ('DeliveryOrderLine', []) ])), ])), ]) # fill attachments for content, name, extension, type in self._attachments: attachment = OrderedDict([ ('AttributeType', type), ('AttributeValue', '%s.%s' % (name, extension)), ]) self.data['DeliveryOrderCreate']['DeliveryOrderHeader']['Attributes']['Attribute'].append(attachment) for move in picking_out.move_lines: # skip lines that are cancelled, missing product_id, or product_id is delivery method or service if move.state == 'cancel' \ or not move.product_id \ or move.id in carrier_move_ids \ or move.product_id.type == 'service': continue # prepare line information line = OrderedDict([ ('LineReference', move.id), ('Item', OrderedDict([ ('ItemAttributes', OrderedDict([ ('Client', 'FW9'), ('Item', move.product_id.ean13), ])), ('SerialCaptureFlag', 'No'), ('QuantityRoundUpRule', 'EXACT'), ('InventorizedItemFlag', 'Yes'), ])), ('OrderQty', move.product_qty), ]) # add line into list of lines and increment line counter self.data['DeliveryOrderCreate']['DeliveryOrderLines']['DeliveryOrderLine'].append(line) return self