diff --git a/base_import_log/__init__.py b/base_import_log/__init__.py index e4f68e2..e283f40 100644 --- a/base_import_log/__init__.py +++ b/base_import_log/__init__.py @@ -18,5 +18,5 @@ # along with this program. If not, see . # ############################################################################## -import models +from . import models # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: \ No newline at end of file diff --git a/base_import_log/models/__init__.py b/base_import_log/models/__init__.py index 5ea3222..5e71ae5 100644 --- a/base_import_log/models/__init__.py +++ b/base_import_log/models/__init__.py @@ -18,6 +18,6 @@ # along with this program. If not, see . # ############################################################################## -import error_log +from . import error_log # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: \ No newline at end of file diff --git a/sale_order_import/__init__.py b/sale_order_import/__init__.py index 8bc92bb..a42433c 100644 --- a/sale_order_import/__init__.py +++ b/sale_order_import/__init__.py @@ -15,7 +15,7 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -import models -import wizard +from . import models +from . import wizard # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: \ No newline at end of file diff --git a/sale_order_import/__openerp__.py b/sale_order_import/__openerp__.py index 642df76..a90bb7e 100644 --- a/sale_order_import/__openerp__.py +++ b/sale_order_import/__openerp__.py @@ -20,7 +20,7 @@ 'category': 'Sales Management', 'version': '8.0.1.0', 'author': 'Rooms For (Hong Kong) T/A OSCG', - 'depends': ['sale_stock', 'base_import_log', 'account_voucher'], + 'depends': ['sale_stock', 'base_import_log', 'account_voucher','sale_management'], 'website': 'www.openerp-asia.net', 'description': """ Imports sales data and processes the following: diff --git a/sale_order_import/doc/ESH_TransactionImportFormats_151022.xlsx b/sale_order_import/doc/ESH_TransactionImportFormats_151022.xlsx new file mode 100644 index 0000000..f1d2867 Binary files /dev/null and b/sale_order_import/doc/ESH_TransactionImportFormats_151022.xlsx differ diff --git a/sale_order_import/doc/TransactionAutomationRequirements.pdf b/sale_order_import/doc/TransactionAutomationRequirements.pdf new file mode 100644 index 0000000..6739229 Binary files /dev/null and b/sale_order_import/doc/TransactionAutomationRequirements.pdf differ diff --git a/sale_order_import/doc/sale_imort_test.csv b/sale_order_import/doc/sale_imort_test.csv new file mode 100644 index 0000000..1971b07 --- /dev/null +++ b/sale_order_import/doc/sale_imort_test.csv @@ -0,0 +1,5 @@ +Group,Customer,Line Product,Line Description,Line Unit Price,Line Qty,Line Tax,Notes,Pricelist,Warehouse,Picking Policy,Order Policy +a,Agrolait,DVD,ニンテンドー3DS シルバー,16000,1,Tax 15.00%,,Public Pricelist,YourCompany,Deliver each product when available,On Demand +a,Agrolait,HEAD,東芝 ロボット掃除機 トルネオ ロボ イエロー VC-RVD1-R,58000,1,Tax 15.00%,,Public Pricelist,YourCompany,Deliver each product when available,On Demand +b,China Export,LAP-E5,PANASONIC MC-RX1S-W レッド RULO(ルーロ) [ロボット掃除機],75000,1,Tax 15.00%,,Public Pricelist,YourCompany,Deliver each product when available,On Demand +c,Best Designers,HEAD,東芝 ロボット掃除機 トルネオ ロボ イエロー VC-RVD1-R,58000,1,Tax 15.00%,,Public Pricelist,YourCompany,Deliver each product when available,On Demand diff --git a/sale_order_import/models/__init__.py b/sale_order_import/models/__init__.py index 4951d10..fed0bed 100644 --- a/sale_order_import/models/__init__.py +++ b/sale_order_import/models/__init__.py @@ -15,7 +15,7 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -import sale -import sale_import_default +from . import sale +from . import sale_import_default # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/sale_order_import/views/sale_import_default.xml b/sale_order_import/views/sale_import_default.xml index 5d3f902..059725d 100644 --- a/sale_order_import/views/sale_import_default.xml +++ b/sale_order_import/views/sale_import_default.xml @@ -24,7 +24,7 @@ + action="sale_import_default_action" sequence="10" groups="sales_team.group_sale_salesman_all_leads"/> diff --git a/sale_order_import/wizard/__init__.py b/sale_order_import/wizard/__init__.py index 7751c8f..9fb1b26 100644 --- a/sale_order_import/wizard/__init__.py +++ b/sale_order_import/wizard/__init__.py @@ -19,6 +19,6 @@ # ############################################################################## -import import_sale +from . import import_sale # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/sale_order_import/wizard/import_sale.py b/sale_order_import/wizard/import_sale.py index 345fd4d..c23ccea 100644 --- a/sale_order_import/wizard/import_sale.py +++ b/sale_order_import/wizard/import_sale.py @@ -17,10 +17,13 @@ import os import csv -import StringIO +import io from tempfile import TemporaryFile from datetime import datetime import base64 +from base64 import encodestring +from odoo.tools import pycompat + # import xlrd import sys import urllib @@ -124,7 +127,8 @@ def _get_taxes(self, tax_from_chunk, taxes, error_line_vals): error_line_vals['error_name'] = error_line_vals['error_name'] + _('Tax: ') + tax_name + _(' Not Found!') + '\n' error_line_vals['error'] = True else: - taxes.append(tax.id) + for taxdata in tax: + taxes.append(taxdata.id) @api.model def _check_csv_format(self, row): @@ -132,7 +136,7 @@ def _check_csv_format(self, row): try: r.decode('utf-8') except: - raise Warning(_('Import Error!'),_('Please prepare a CSV file with UTF-8 encoding.!')) + raise Warning(_('Please prepare a CSV file with UTF-8 encoding.!')) @api.model def _update_error_log(self, error_log_id, error_line_vals, ir_attachment, model, row_no, order_group_value): @@ -160,17 +164,17 @@ def _update_error_log(self, error_log_id, error_line_vals, ir_attachment, model, @api.model def _get_order_id(self, order_data, item, error_log_id): order_vals = { - 'name' : '/', + 'name' : 'New', #'/', # odoo11 'partner_id' : order_data['partner_id'], 'partner_invoice_id' : order_data['partner_invoice_id'], 'pricelist_id' : order_data['pricelist_id'], - 'location_id': order_data['location_id'], +# 'location_id': order_data['location_id'], # odoo11 'partner_shipping_id' : order_data['partner_shipping_id'], - 'payment_term': order_data['payment_term'], + 'payment_term_id': order_data['payment_term'], 'state' : 'draft', - 'order_policy' : order_data['order_policy'], +# 'order_policy' : order_data['order_policy'], # odoo11 'picking_policy': order_data['picking_policy'], - 'currency_id' : order_data['currency_id'], +# 'currency_id' : order_data['currency_id'], # odoo11 'note': order_data['note'], 'error_log_id': error_log_id, 'imported_order': True, @@ -186,7 +190,7 @@ def _get_orderline_id(self, so_line, order_id): 'product_id' : so_line['product_id'], 'product_uom_qty' : so_line['product_uom_qty'], 'product_uom': so_line['product_uom'], - 'invoiced' : False, +# 'invoiced' : False, # odoo11 'price_unit' : so_line['price_unit'], 'state' : so_line['state'], 'tax_id': [(6, 0, so_line['tax_id'])], @@ -230,26 +234,48 @@ def import_sale_data(self): 'datas': self.input_file, 'datas_fname': self.datas_fname}) - fileobj = TemporaryFile('w+') - fileobj.write(base64.decodestring(self.input_file)) - fileobj.seek(0) - reader = csv.reader(fileobj) - - line = 0 - for row in reader: - line += 1 - if line == 1:#Get the index of header and skip the first line - order_group = row.index('Group') - partner_id = row.index('Customer') - product_id = row.index('Line Product') - line_name = row.index('Line Description') - price_unit = row.index('Line Unit Price') - product_qty = row.index('Line Qty') - taxes_id = row.index('Line Tax') - notes = row.index('Notes') - pricelist_id = row.index('Pricelist') - warehouse_id = row.index('Warehouse') - continue +# fileobj = TemporaryFile('w+') +# fileobj.write(base64.b64decode(self.input_file)) +# fileobj.seek(0) +# reader = csv.reader(fileobj) + + # new code to read csv + csv_data = base64.decodestring(self.input_file) + csv_iterator = pycompat.csv_reader( + io.BytesIO(csv_data), + quotechar='"', + delimiter=',' + ) + fields = next(csv_iterator) + + order_group = fields.index('Group') + partner_id = fields.index('Customer') + product_id = fields.index('Line Product') + line_name = fields.index('Line Description') + price_unit = fields.index('Line Unit Price') + product_qty = fields.index('Line Qty') + taxes_id = fields.index('Line Tax') + notes = fields.index('Notes') + pricelist_id = fields.index('Pricelist') + warehouse_id = fields.index('Warehouse') + +# line = 1 + for row in csv_iterator: +# line += 1 + +# if line == 1:#Get the index of header and skip the first line +# +# order_group = row.index('Group') +# partner_id = row.index('Customer') +# product_id = row.index('Line Product') +# line_name = row.index('Line Description') +# price_unit = row.index('Line Unit Price') +# product_qty = row.index('Line Qty') +# taxes_id = row.index('Line Tax') +# notes = row.index('Notes') +# pricelist_id = row.index('Pricelist') +# warehouse_id = row.index('Warehouse') +# continue check_list = []# Below logic for is row values are empty on all columns then skip that line. order_group_value = row[order_group].strip() @@ -258,10 +284,10 @@ def import_sale_data(self): if bool(r.strip()): check_list.append(r) if not bool(row[order_group].strip()) and not check_list: - continue + continue - if line == 2:#Check for UTF-8 Format. Only for first line i.e. line=2. - self._check_csv_format(row) +# if line == 2:#Check for UTF-8 Format. Only for first line i.e. line=2. +# self._check_csv_format(row) error_line_vals = {'error_name' : '', 'error': False} partner_value = row[partner_id].strip() @@ -270,28 +296,28 @@ def import_sale_data(self): error_line_vals['error'] = True else: self._get_partner_dict(partner_value, partner_dict, error_line_vals) - + product_id_value = row[product_id].strip() if not product_id_value: error_line_vals['error_name'] = error_line_vals['error_name'] + _('Product is empty!') + '\n' error_line_vals['error'] = True else: self._get_product_dict(product_id_value, product_dict, error_line_vals) - + pricelist_value = row[pricelist_id].strip() if not pricelist_value: error_line_vals['error_name'] = error_line_vals['error_name'] + _('Pricelist is empty!') + '\n' error_line_vals['error'] = True else: self._get_pricelist_dict(pricelist_value, pricelist_dict, error_line_vals) - + warehouse_value = row[warehouse_id].strip() if not warehouse_value: error_line_vals['error_name'] = error_line_vals['error_name'] + _('Warehouse is empty!') + '\n' error_line_vals['error'] = True else: self._get_picking_dict(warehouse_value, picking_dict, error_line_vals) - + taxes = [] tax_from_chunk = row[taxes_id].strip() if tax_from_chunk: @@ -303,41 +329,44 @@ def import_sale_data(self): error_line_vals['error'] = True else: qty = float(qty) - + if qty <= 0: error_line_vals['error_name'] = error_line_vals['error_name'] + _('Quantity not less than zero!') + '\n' error_line_vals['error'] = True - + price_unit_value = row[price_unit].strip() if not price_unit_value: error_line_vals['error_name'] = error_line_vals['error_name'] + _('Unit Price is empty!') + '\n' error_line_vals['error'] = True else: price_unit_value = float(price_unit_value) - + if price_unit_value <= 0: error_line_vals['error_name'] = error_line_vals['error_name'] + _('Unit Price not less than zero!') + '\n' error_line_vals['error'] = True - + order_policy = self.order_policy picking_policy = self.picking_policy order = row[order_group].strip() - + error_log_id = self._update_error_log(error_log_id, error_line_vals, ir_attachment, model, line, order) - + if not error_log_id: name = row[line_name].strip() - - product_data = self.env['sale.order.line'].product_id_change(pricelist_dict[pricelist_value], product_dict[product_id_value], qty, False, 0, False, '', partner_dict[partner_value],False, True, False, False, False, False) +# product_data = self.env['sale.order.line'].product_id_change(pricelist_dict[pricelist_value], product_dict[product_id_value], qty, False, 0, False, '', partner_dict[partner_value],False, True, False, False, False, False) +# product_data = self.env['sale.order.line'].product_id_change() + product_data = self.env['product.product'].browse(product_dict[product_id_value]) # odoo11 if not name: name = product_data['value']['name'] + state = 'draft' if order not in order_item_dict.keys(): order_item_dict[order] = [{ 'name' : name, 'product_id' : product_dict[product_id_value], 'product_uom_qty' : qty, - 'product_uom' : product_data['value']['product_uom'], +# 'product_uom' : product_data['value']['product_uom'], # odoo11 + 'product_uom' : product_data.uom_id.id, 'price_unit' : price_unit_value, 'state' : state, 'tax_id':taxes, @@ -347,28 +376,34 @@ def import_sale_data(self): 'name' : name, 'product_id' : product_dict[product_id_value], 'product_uom_qty' : qty, - 'product_uom' : product_data['value']['product_uom'], +# 'product_uom' : product_data['value']['product_uom'],# odoo11 + 'product_uom' : product_data.uom_id.id, 'price_unit' : price_unit_value, 'state' : state, 'tax_id':taxes, }) - + if order not in order_dict: - pricelist_data = self.env['sale.order'].onchange_pricelist_id(pricelist_dict[pricelist_value], False) - partner_data = self.env['sale.order'].onchange_partner_id(partner_dict[partner_value]) +# pricelist_data = self.env['sale.order'].onchange_pricelist_id(pricelist_dict[pricelist_value], False) +# partner_data = self.env['sale.order'].onchange_partner_id(partner_dict[partner_value]) + partner_data = self.env['res.partner'].browse(partner_dict[partner_value]) + pricelist_data = partner_data.property_product_pricelist and partner_data.property_product_pricelist.id or False + addr = partner_data.address_get(['delivery', 'invoice']) order_dict[order] = { 'partner_id' : partner_dict[partner_value], - 'partner_invoice_id' : partner_data['value']['partner_invoice_id'], +# 'partner_invoice_id' : partner_data['value']['partner_invoice_id'], # odoo11 + 'partner_invoice_id' : addr['invoice'], 'pricelist_id' : pricelist_dict[pricelist_value], 'location_id': picking_dict[warehouse_value].default_location_dest_id and picking_dict[warehouse_value].default_location_dest_id.id, - 'partner_shipping_id' : partner_data['value']['partner_shipping_id'], - 'payment_term': partner_data['value']['payment_term'], +# 'partner_shipping_id' : partner_data['value']['partner_shipping_id'], # odoo11 + 'partner_shipping_id' : addr['delivery'], +# 'payment_term': partner_data['value']['payment_term'], # odoo11 + 'payment_term': partner_data.property_payment_term_id and partner_data.property_payment_term_id.id or False, 'order_policy' : order_policy, 'picking_policy': picking_policy, - 'currency_id' : pricelist_data['value']['currency_id'], +# 'currency_id' : pricelist_data['value']['currency_id'], # odoo11 'note': row[notes].strip() } - if not error_log_id: error_log_id = self.env['error.log'].create({'input_file': ir_attachment.id, 'import_user_id' : self.env.user.id, @@ -382,74 +417,83 @@ def import_sale_data(self): for so_line in order_item_dict[item]: orderline_id = self._get_orderline_id(so_line, order_id) - order_id.signal_workflow('order_confirm') +# order_id.signal_workflow('order_confirm') # odoo11 + order_id.action_confirm() # odoo11 if order_id.picking_ids: for picking in order_id.picking_ids: available = picking.action_assign() - if order_id.order_policy == 'picking': +# if order_id.order_policy == 'picking': # odoo11 TODO + if self.order_policy == 'picking': # TODO check now order policy removed from sale order it is on product pass #IF INVOICE POLICY IS FROM DELIVERY ORDER THEN WE WILL NOT CREATE INVOICE FROM HERE AND WE WILL PROCESS/CREATE INVOICE WHILE IMPORTING PICKINGS CSV. MEANS PICKING WILL BE HAVING STATE 2BINVOICED WILL BE PROCESS INVOICE/PAYMENT WHILE IMPORTING PICKING CSV. #invoice = picking.action_invoice_create( # journal_id = self.customer_invoice_journal_id.id, # type = 'out_invoice' # ) - if order_id.state == 'manual' or order_id.state == 'prepaid': - invoice = order_id.signal_workflow('manual_invoice') + +# if order_id.state == 'manual' or order_id.state == 'prepaid': +# invoice = order_id.signal_workflow('manual_invoice') # odoo 11 + + invoice_ids = order_id.action_invoice_create() # odoo11 + if order_id.invoice_ids: for invoice in order_id.invoice_ids: invoice.journal_id = self.customer_invoice_journal_id.id if invoice.state == 'draft': - invoice.signal_workflow('invoice_open') - if self.customer_payment_journal_id.currency and self.customer_payment_journal_id.currency.id != invoice.currency_id.id: - currency_id_voucher = self.customer_payment_journal_id.currency.id - voucher_amount = invoice.currency_id.compute(invoice.amount_total, self.customer_payment_journal_id.currency) - elif not self.customer_payment_journal_id.currency and invoice.currency_id.id != invoice.company_id.currency_id.id: - currency_id_voucher = invoice.company_id.currency_id.id - voucher_amount = invoice.currency_id.compute(invoice.amount_total, invoice.company_id.currency_id) - else: - currency_id_voucher = invoice.currency_id.id - voucher_amount = invoice.amount_total - partner_data = self.env['account.voucher'].onchange_partner_id(invoice.partner_id.id, - self.customer_payment_journal_id.id, - voucher_amount, - currency_id_voucher, - 'receipt', - invoice.date_invoice) - journal_data = self.env['account.voucher'].onchange_journal_voucher(line_ids= False, - tax_id=False, - price=0.0, - partner_id=invoice.partner_id.id, - journal_id=self.customer_payment_journal_id.id, - ttype='receipt', - company_id=invoice.company_id.id) - line_cr_list = [] - for line in partner_data['value']['line_cr_ids']: - moveline = self.env['account.move.line'].browse(line['move_line_id']) - if invoice.id == moveline.invoice.id: - line['amount'] = voucher_amount - line_cr_list.append((0, 0, line)) - break #IF one line found then get out of loop since invoice and payment has one to one relation. - voucher_vals = { - 'name': '/', - 'partner_id' : invoice.partner_id.id, - 'company_id' : invoice.company_id.id, - 'journal_id' : self.customer_payment_journal_id.id, - 'currency_id': currency_id_voucher, - 'line_ids' : False, - 'line_cr_ids' : line_cr_list, - 'line_dr_ids' : False, - 'account_id' : partner_data['value']['account_id'], - 'period_id': journal_data['value']['period_id'], - 'state': 'draft', - 'date' : invoice.date_invoice, - 'type': 'receipt', - 'amount' : voucher_amount, - 'payment_rate': journal_data['value']['payment_rate'], - 'payment_rate_currency_id': journal_data['value']['payment_rate_currency_id'] - } - voucher_id = self.env['account.voucher'].create(voucher_vals) - voucher_id.signal_workflow('proforma_voucher') - +# invoice.signal_workflow('invoice_open') + invoice.action_invoice_open() # odoo11 + invoice.pay_and_reconcile(self.customer_payment_journal_id.id) # odoo11 + + # no need to create manual payment we have odoo standard method to do this so just called it +# if self.customer_payment_journal_id.currency and self.customer_payment_journal_id.currency.id != invoice.currency_id.id: +# currency_id_voucher = self.customer_payment_journal_id.currency.id +# voucher_amount = invoice.currency_id.compute(invoice.amount_total, self.customer_payment_journal_id.currency) +# elif not self.customer_payment_journal_id.currency and invoice.currency_id.id != invoice.company_id.currency_id.id: +# currency_id_voucher = invoice.company_id.currency_id.id +# voucher_amount = invoice.currency_id.compute(invoice.amount_total, invoice.company_id.currency_id) +# else: +# currency_id_voucher = invoice.currency_id.id +# voucher_amount = invoice.amount_total +# partner_data = self.env['account.voucher'].onchange_partner_id(invoice.partner_id.id, +# self.customer_payment_journal_id.id, +# voucher_amount, +# currency_id_voucher, +# 'receipt', +# invoice.date_invoice) +# journal_data = self.env['account.voucher'].onchange_journal_voucher(line_ids= False, +# tax_id=False, +# price=0.0, +# partner_id=invoice.partner_id.id, +# journal_id=self.customer_payment_journal_id.id, +# ttype='receipt', +# company_id=invoice.company_id.id) +# line_cr_list = [] +# for line in partner_data['value']['line_cr_ids']: +# moveline = self.env['account.move.line'].browse(line['move_line_id']) +# if invoice.id == moveline.invoice.id: +# line['amount'] = voucher_amount +# line_cr_list.append((0, 0, line)) +# break #IF one line found then get out of loop since invoice and payment has one to one relation. +# voucher_vals = { +# 'name': '/', +# 'partner_id' : invoice.partner_id.id, +# 'company_id' : invoice.company_id.id, +# 'journal_id' : self.customer_payment_journal_id.id, +# 'currency_id': currency_id_voucher, +# 'line_ids' : False, +# 'line_cr_ids' : line_cr_list, +# 'line_dr_ids' : False, +# 'account_id' : partner_data['value']['account_id'], +# 'period_id': journal_data['value']['period_id'], +# 'state': 'draft', +# 'date' : invoice.date_invoice, +# 'type': 'receipt', +# 'amount' : voucher_amount, +# 'payment_rate': journal_data['value']['payment_rate'], +# 'payment_rate_currency_id': journal_data['value']['payment_rate_currency_id'] +# } +# voucher_id = self.env['account.voucher'].create(voucher_vals) +# voucher_id.signal_workflow('proforma_voucher') res = self.env.ref('base_import_log.error_log_action') res = res.read()[0] res['domain'] = str([('id','in',[error_log_id])]) diff --git a/sale_order_import/wizard/import_sale_view.xml b/sale_order_import/wizard/import_sale_view.xml index 318bd01..c66dda9 100644 --- a/sale_order_import/wizard/import_sale_view.xml +++ b/sale_order_import/wizard/import_sale_view.xml @@ -6,13 +6,14 @@ error.log - - + + +
-
+