From db05922bfc1550c7df448bf551ce2562420c2003 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Valyi?= Date: Mon, 22 Feb 2010 02:35:21 -0300 Subject: [PATCH 01/35] [REF] splits account.invoice#action_move_create method that is too fat into overridable bits; doesn't change any logic; add comments bzr revid: rvalyi@gmail.com-20100222053521-m2z3b84kc35eluys --- addons/account/invoice.py | 136 ++++++++++++++++++++++---------------- 1 file changed, 80 insertions(+), 56 deletions(-) diff --git a/addons/account/invoice.py b/addons/account/invoice.py index 912095110e7..0168052027e 100644 --- a/addons/account/invoice.py +++ b/addons/account/invoice.py @@ -630,8 +630,85 @@ class account_invoice(osv.osv): if res and res['value']: self.write(cr, uid, [inv.id], res['value']) return True + + def check_tax_lines(self, cr, uid, inv, compute_taxes, ait_obj): + if not inv.tax_line: + for tax in compute_taxes.values(): + ait_obj.create(cr, uid, tax) + else: + tax_key = [] + for tax in inv.tax_line: + if tax.manual: + continue + key = (tax.tax_code_id.id, tax.base_code_id.id, tax.account_id.id) + tax_key.append(key) + if not key in compute_taxes: + raise osv.except_osv(_('Warning !'), _('Global taxes defined, but are not in invoice lines !')) + base = compute_taxes[key]['base'] + if abs(base - tax.base) > inv.company_id.currency_id.rounding: + raise osv.except_osv(_('Warning !'), _('Tax base different !\nClick on compute to update tax base')) + for key in compute_taxes: + if not key in tax_key: + raise osv.except_osv(_('Warning !'), _('Taxes missing !')) + + def compute_invoice_totals(self, cr, uid, inv, company_currency, ref, invoice_move_lines): + total = 0 + total_currency = 0 + for i in invoice_move_lines: + if inv.currency_id.id != company_currency: + i['currency_id'] = inv.currency_id.id + i['amount_currency'] = i['price'] + i['price'] = cur_obj.compute(cr, uid, inv.currency_id.id, + company_currency, i['price'], + context={'date': inv.date_invoice or time.strftime('%Y-%m-%d')}) + else: + i['amount_currency'] = False + i['currency_id'] = False + i['ref'] = ref + if inv.type in ('out_invoice','in_refund'): + total += i['price'] + total_currency += i['amount_currency'] or i['price'] + i['price'] = - i['price'] + else: + total -= i['price'] + total_currency -= i['amount_currency'] or i['price'] + return total, total_currency, invoice_move_lines + + def inv_line_characteristic_hashcode(self, invoice, invoice_line): + """Overridable hashcode generation for invoice lines. Lines having the same hashcode + will be grouped together if the journal has the 'group line' option. Of course a module + can add fields to invoice lines that would need to be tested too before merging lines + or not.""" + code = str(invoice_line['account_id']) + code += '-'+str(invoice_line.get('tax_code_id',"False")) + code += '-'+str(invoice_line.get('product_id',"False")) + code += '-'+str(invoice_line.get('analytic_account_id',"False")) + code += '-'+str(invoice_line.get('date_maturity',"False")) + return code + + def group_lines(self, cr, uid, iml, line, inv): + """Groups account move lines (and hence analytic lines) eventually if invoice line hashcodes are equal""" + if inv.journal_id.group_invoice_lines: + line2 = {} + for x, y, l in line: + tmp = self.inv_line_characteristic_hashcode(inv, l) + + if tmp in line2: + am = line2[tmp]['debit'] - line2[tmp]['credit'] + (l['debit'] - l['credit']) + line2[tmp]['debit'] = (am > 0) and am or 0.0 + line2[tmp]['credit'] = (am < 0) and -am or 0.0 + line2[tmp]['tax_amount'] += l['tax_amount'] + line2[tmp]['analytic_lines'] += l['analytic_lines'] + else: + line2[tmp] = l + line = [] + for key, val in line2.items(): + line.append((0,0,val)) + + return line def action_move_create(self, cr, uid, ids, *args): + """Creates invoice related analytics and financial move lines""" ait_obj = self.pool.get('account.invoice.tax') cur_obj = self.pool.get('res.currency') context = {} @@ -650,24 +727,7 @@ class account_invoice(osv.osv): context.update({'lang': inv.partner_id.lang}) compute_taxes = ait_obj.compute(cr, uid, inv.id, context=context) - if not inv.tax_line: - for tax in compute_taxes.values(): - ait_obj.create(cr, uid, tax) - else: - tax_key = [] - for tax in inv.tax_line: - if tax.manual: - continue - key = (tax.tax_code_id.id, tax.base_code_id.id, tax.account_id.id) - tax_key.append(key) - if not key in compute_taxes: - raise osv.except_osv(_('Warning !'), _('Global taxes defined, but are not in invoice lines !')) - base = compute_taxes[key]['base'] - if abs(base - tax.base) > inv.company_id.currency_id.rounding: - raise osv.except_osv(_('Warning !'), _('Tax base different !\nClick on compute to update tax base')) - for key in compute_taxes: - if not key in tax_key: - raise osv.except_osv(_('Warning !'), _('Taxes missing !')) + self.check_tax_lines(cr, uid, inv, compute_taxes, ait_obj) if inv.type in ('in_invoice', 'in_refund') and abs(inv.check_total - inv.amount_total) >= (inv.currency_id.rounding/2.0): raise osv.except_osv(_('Bad total !'), _('Please verify the price of the invoice !\nThe real total does not match the computed total.')) @@ -684,24 +744,7 @@ class account_invoice(osv.osv): # create one move line for the total and possibly adjust the other lines amount total = 0 total_currency = 0 - for i in iml: - if inv.currency_id.id != company_currency: - i['currency_id'] = inv.currency_id.id - i['amount_currency'] = i['price'] - i['price'] = cur_obj.compute(cr, uid, inv.currency_id.id, - company_currency, i['price'], - context={'date': inv.date_invoice or time.strftime('%Y-%m-%d')}) - else: - i['amount_currency'] = False - i['currency_id'] = False - i['ref'] = ref - if inv.type in ('out_invoice','in_refund'): - total += i['price'] - total_currency += i['amount_currency'] or i['price'] - i['price'] = - i['price'] - else: - total -= i['price'] - total_currency -= i['amount_currency'] or i['price'] + total, total_currency, iml = self.compute_invoice_totals(cr, uid, inv, company_currency, ref, iml) acc_id = inv.account_id.id name = inv['name'] or '/' @@ -756,26 +799,7 @@ class account_invoice(osv.osv): line = map(lambda x:(0,0,self.line_get_convert(cr, uid, x, part, date, context={})) ,iml) - if inv.journal_id.group_invoice_lines: - line2 = {} - for x, y, l in line: - tmp = str(l['account_id']) - tmp += '-'+str(l.get('tax_code_id',"False")) - tmp += '-'+str(l.get('product_id',"False")) - tmp += '-'+str(l.get('analytic_account_id',"False")) - tmp += '-'+str(l.get('date_maturity',"False")) - - if tmp in line2: - am = line2[tmp]['debit'] - line2[tmp]['credit'] + (l['debit'] - l['credit']) - line2[tmp]['debit'] = (am > 0) and am or 0.0 - line2[tmp]['credit'] = (am < 0) and -am or 0.0 - line2[tmp]['tax_amount'] += l['tax_amount'] - line2[tmp]['analytic_lines'] += l['analytic_lines'] - else: - line2[tmp] = l - line = [] - for key, val in line2.items(): - line.append((0,0,val)) + line = self.group_lines(cr, uid, iml, line, inv) journal_id = inv.journal_id.id #self._get_journal(cr, uid, {'type': inv['type']}) journal = self.pool.get('account.journal').browse(cr, uid, journal_id) From 870be4ea1b287f0a3fc7a820d910f627e6906fd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Valyi?= Date: Tue, 23 Feb 2010 02:38:30 -0300 Subject: [PATCH 02/35] [REF] account: changed invoice#group_lines extract method comments as suggested by Xavier Morel bzr revid: rvalyi@gmail.com-20100223053830-yp71uc06fktjuzim --- addons/account/invoice.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/account/invoice.py b/addons/account/invoice.py index 0168052027e..3dd30d7293a 100644 --- a/addons/account/invoice.py +++ b/addons/account/invoice.py @@ -687,7 +687,7 @@ class account_invoice(osv.osv): return code def group_lines(self, cr, uid, iml, line, inv): - """Groups account move lines (and hence analytic lines) eventually if invoice line hashcodes are equal""" + """Merge account move lines (and hence analytic lines) if invoice line hashcodes are equals""" if inv.journal_id.group_invoice_lines: line2 = {} for x, y, l in line: From ab5585e42dc8f5dddc160e7f6a3293196721bfc7 Mon Sep 17 00:00:00 2001 From: "rpa (Open ERP)" Date: Wed, 24 Feb 2010 12:06:01 +0530 Subject: [PATCH 03/35] [IMP]: crm(meeting): Put Deadline as datetime bzr revid: rpa@openerp.co.in-20100224063601-if0o1c86ec30dn4p --- addons/crm/crm_meeting.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/addons/crm/crm_meeting.py b/addons/crm/crm_meeting.py index 87fc11a2591..4027c097227 100644 --- a/addons/crm/crm_meeting.py +++ b/addons/crm/crm_meeting.py @@ -27,9 +27,13 @@ from datetime import datetime, timedelta class crm_opportunity(osv.osv): _name = 'crm.opportunity' crm_opportunity() + + class crm_phonecall(osv.osv): _name = 'crm.phonecall' -crm_phonecall() +crm_phonecall() + + class crm_meeting(osv.osv): _name = 'crm.meeting' _description = "Meeting Cases" @@ -44,7 +48,8 @@ class crm_meeting(osv.osv): 'phonecall_id':fields.many2one ('crm.phonecall', 'Phonecall'), 'opportunity_id':fields.many2one ('crm.opportunity', 'Opportunity'), 'attendee_ids': fields.many2many('calendar.attendee', 'event_attendee_rel', 'event_id', 'attendee_id', 'Attendees'), - 'date_closed': fields.datetime('Closed', readonly=True), + 'date_closed': fields.datetime('Closed', readonly=True), + 'date_deadline': fields.datetime('Deadline'), } crm_meeting() From c4a5925fb0ea6191531b93530d7f14b03542b013 Mon Sep 17 00:00:00 2001 From: "mra (Open ERP)" Date: Wed, 24 Feb 2010 12:06:48 +0530 Subject: [PATCH 04/35] [FIX] account_analytic_default: product_id_change on invoice line argument mismatch with super method bzr revid: mra@tinyerp.com-20100224063648-fywwzv2b11atf35z --- .../account_analytic_default.py | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/addons/account_analytic_default/account_analytic_default.py b/addons/account_analytic_default/account_analytic_default.py index f22e37e5e71..ab81e7d88fc 100644 --- a/addons/account_analytic_default/account_analytic_default.py +++ b/addons/account_analytic_default/account_analytic_default.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- ############################################################################### -# +# # OpenERP, Open Source Management Solution # Copyright (C) 2004-2010 Tiny SPRL (). # @@ -15,7 +15,7 @@ # GNU Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . +# along with this program. If not, see . # ############################################################################## @@ -70,51 +70,51 @@ account_analytic_default() class account_invoice_line(osv.osv): _inherit = 'account.invoice.line' _description = 'account invoice line' - - def product_id_change(self, cr, uid, ids, product, uom, qty=0, name='', type='out_invoice', partner_id=False, fposition=False, price_unit=False, address_invoice_id=False, context={}): - res_prod = super(account_invoice_line,self).product_id_change(cr, uid, ids, product, uom, qty, name, type, partner_id, fposition, price_unit, address_invoice_id, context) + + def product_id_change(self, cr, uid, ids, product, uom, qty=0, name='', type='out_invoice', partner_id=False, fposition=False, price_unit=False, address_invoice_id=False, currency_id=False, context={}): + res_prod = super(account_invoice_line,self).product_id_change(cr, uid, ids, product, uom, qty, name, type, partner_id, fposition, price_unit, address_invoice_id, currency_id=currency_id, context=context) rec = self.pool.get('account.analytic.default').account_get(cr, uid, product, partner_id, uid, time.strftime('%Y-%m-%d'), context) if rec: res_prod['value'].update({'account_analytic_id':rec.analytic_id.id}) else: - res_prod['value'].update({'account_analytic_id':False}) + res_prod['value'].update({'account_analytic_id':False}) return res_prod account_invoice_line() class stock_picking(osv.osv): _inherit = "stock.picking" - + def _get_account_analytic_invoice(self, cursor, user, picking, move_line): partner_id = picking.address_id and picking.address_id.partner_id or False rec = self.pool.get('account.analytic.default').account_get(cursor, user, move_line.product_id.id, partner_id and partner_id.id, user, time.strftime('%Y-%m-%d'), context={}) - + if rec: return rec.analytic_id.id - + return super(stock_picking, self)._get_account_analytic_invoice(cursor, user, picking, move_line) - + stock_picking() class sale_order_line(osv.osv): _inherit = 'sale.order.line' - + # Method overridden to set the analytic account by default on criterion match def invoice_line_create(self, cr, uid, ids, context={}): create_ids = super(sale_order_line,self).invoice_line_create(cr, uid, ids, context) sale_line_obj = self.browse(cr, uid, ids[0], context) pool_inv_line = self.pool.get('account.invoice.line') - + for line in pool_inv_line.browse(cr, uid, create_ids, context): rec = self.pool.get('account.analytic.default').account_get(cr, uid, line.product_id.id, sale_line_obj.order_id.partner_id.id, uid, time.strftime('%Y-%m-%d'), context) - + if rec: pool_inv_line.write(cr, uid, [line.id], {'account_analytic_id':rec.analytic_id.id}, context=context) return create_ids - -sale_order_line() - + +sale_order_line() + # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: From b778634da1108d8c935d09d23ef264ccb4a68975 Mon Sep 17 00:00:00 2001 From: "mra (Open ERP)" Date: Wed, 24 Feb 2010 12:51:14 +0530 Subject: [PATCH 05/35] [IMP] membership: invoice membership wizard now open list of invoice with its search view bzr revid: mra@tinyerp.com-20100224072114-naekglazd0envj7l --- addons/membership/wizard/invoice_membership.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/addons/membership/wizard/invoice_membership.py b/addons/membership/wizard/invoice_membership.py index dc607622140..2eb63ad6c96 100644 --- a/addons/membership/wizard/invoice_membership.py +++ b/addons/membership/wizard/invoice_membership.py @@ -82,6 +82,9 @@ def _invoice_membership(self, cr, uid, data, context): for tax in tax_value: invoice_tax_obj.create(cr, uid, tax, context=context) + result = pool.get('ir.model.data')._get_id(cr, uid, 'account', 'view_account_invoice_filter') + res = pool.get('ir.model.data').read(cr, uid, result, ['res_id']) + value = { 'domain': [ ('id', 'in', invoice_list), @@ -91,6 +94,8 @@ def _invoice_membership(self, cr, uid, data, context): 'view_mode': 'tree,form', 'res_model': 'account.invoice', 'type': 'ir.actions.act_window', + 'res_id' : invoice_list, + 'search_view_id' : res['res_id'] } return value From 03ff37e5f640c02d5bed3291b1b97cee37418483 Mon Sep 17 00:00:00 2001 From: "Harry (Open ERP)" Date: Wed, 24 Feb 2010 13:47:06 +0530 Subject: [PATCH 06/35] [IMP] mrp: add new wizard for produce product and change workflow of production order bzr revid: hmo@tinyerp.com-20100224081706-x156eauvbp3btnwp --- addons/mrp/__init__.py | 1 + addons/mrp/__terp__.py | 1 + addons/mrp/mrp.py | 93 ++++++++++++++++++++++++++-------- addons/mrp/mrp_view.xml | 6 +-- addons/mrp/mrp_wizard.py | 59 +++++++++++++++++++++ addons/mrp/mrp_wizard_view.xml | 41 +++++++++++++++ addons/mrp/mrp_workflow.xml | 3 +- addons/stock/stock.py | 55 ++++++++++++-------- 8 files changed, 210 insertions(+), 49 deletions(-) create mode 100644 addons/mrp/mrp_wizard.py create mode 100644 addons/mrp/mrp_wizard_view.xml diff --git a/addons/mrp/__init__.py b/addons/mrp/__init__.py index 90ca012bc48..b219d932141 100644 --- a/addons/mrp/__init__.py +++ b/addons/mrp/__init__.py @@ -21,6 +21,7 @@ import mrp import installer +import mrp_wizard import wizard import report import company diff --git a/addons/mrp/__terp__.py b/addons/mrp/__terp__.py index 3bf2410cff9..1d5eb98da2e 100644 --- a/addons/mrp/__terp__.py +++ b/addons/mrp/__terp__.py @@ -60,6 +60,7 @@ 'security/ir.model.access.csv', 'mrp_workflow.xml', 'mrp_data.xml', + 'mrp_wizard_view.xml', 'mrp_view.xml', 'mrp_wizard.xml', 'mrp_report.xml', diff --git a/addons/mrp/mrp.py b/addons/mrp/mrp.py index dbcf6c989ed..9897e3e7825 100644 --- a/addons/mrp/mrp.py +++ b/addons/mrp/mrp.py @@ -581,28 +581,78 @@ class mrp_production(osv.osv): {'location_id':production.location_dest_id.id}) return True - #TODO Review materials in function in_prod and prod_end. def action_production_end(self, cr, uid, ids): - move_ids = [] for production in self.browse(cr, uid, ids): - for res in production.move_lines: - for move in production.move_created_ids: - #XXX must use the orm - cr.execute('INSERT INTO stock_move_history_ids \ - (parent_id, child_id) VALUES (%s,%s)', - (res.id, move.id)) - move_ids.append(res.id) - vals= {'state':'confirmed'} - new_moves = [x.id for x in production.move_created_ids] - self.pool.get('stock.move').write(cr, uid, new_moves, vals) - if not production.date_finnished: - self.write(cr, uid, [production.id], - {'date_finnished': time.strftime('%Y-%m-%d %H:%M:%S')}) - self.pool.get('stock.move').check_assign(cr, uid, new_moves) - self.pool.get('stock.move').action_done(cr, uid, new_moves) self._costs_generate(cr, uid, production) - self.pool.get('stock.move').action_done(cr, uid, move_ids) - self.write(cr, uid, ids, {'state': 'done'}) + return self.write(cr, uid, ids, {'state': 'done', 'date_finnished': time.strftime('%Y-%m-%d %H:%M:%S')}) + + def test_production_done(self, cr, uid, ids): + res = True + for production in self.browse(cr, uid, ids): + if production.move_lines: + res = False + + if production.move_created_ids: + res = False + return res + + def do_produce(self, cr, uid, production_id, production_qty, production_mode, context=None): + stock_mov_obj = self.pool.get('stock.move') + production = self.browse(cr, uid, production_id) + + raw_product_todo = [] + final_product_todo = [] + + if production_mode in ['consume','consume_produce']: + consumed_products = {} + produced_qty = 0 + for consumed_product in production.move_lines2: + if not consumed_products.get(consumed_product.product_id.id, False): + consumed_products[consumed_product.product_id.id] = 0 + consumed_products[consumed_product.product_id.id] += consumed_product.product_qty + + for produced_product in production.move_created_ids2: + produced_qty += produced_product.product_qty + + for raw_product in production.move_lines: + consumed_qty = consumed_products.get(raw_product.product_id.id, 0) + consumed_qty -= produced_qty + rest_qty = production_qty - consumed_qty + if rest_qty > production.product_qty: + rest_qty = production.product_qty + if rest_qty > 0: + stock_mov_obj.consume_moves(cr, uid, [raw_product.id], rest_qty, production.location_src_id.id, context=context) + + if production_mode == 'consume_produce': + vals = {'state':'confirmed'} + final_product_todo = [x.id for x in production.move_created_ids] + stock_mov_obj.write(cr, uid, final_product_todo, vals) + produced_products = {} + for produced_product in production.move_created_ids2: + if not produced_products.get(produced_product.product_id.id, False): + produced_products[produced_product.product_id.id] = 0 + produced_products[produced_product.product_id.id] += produced_product.product_qty + + for produce_product in production.move_created_ids: + produced_qty = produced_products.get(produce_product.product_id.id, 0) + rest_qty = production.product_qty - produced_qty + if rest_qty <= production_qty: + production_qty = rest_qty + if rest_qty > 0 : + stock_mov_obj.consume_moves(cr, uid, [produce_product.id], production_qty, production.location_dest_id.id, context=context) + + + for raw_product in production.move_lines2: + new_parent_ids = [] + parent_move_ids = [x.id for x in raw_product.move_history_ids] + for final_product in production.move_created_ids2: + if final_product.id not in parent_move_ids: + new_parent_ids.append(final_product.id) + for new_parent_id in new_parent_ids: + stock_mov_obj.write(cr, uid, [raw_product.id], {'move_history_ids':[(4,new_parent_id)]}) + + wf_service = netsvc.LocalService("workflow") + wf_service.trg_validate(uid, 'mrp.production', production_id, 'button_produce_done', cr) return True def _costs_generate(self, cr, uid, production): @@ -1285,8 +1335,7 @@ class StockMove(osv.osv): state = 'confirmed' if move.state=='assigned': state='assigned' - for line in res[0]: - print 'Line :',line + for line in res[0]: valdef = { 'picking_id': move.picking_id.id, 'product_id': line['product_id'], @@ -1337,7 +1386,7 @@ class StockMove(osv.osv): res = [] production_obj = self.pool.get('mrp.production') for move in self.browse(cr, uid, ids): - new_moves = super(StockMove, self).consume_moves(cr, uid, ids, product_qty, location_id, context=context) + new_moves = super(StockMove, self).consume_moves(cr, uid, [move.id], product_qty, location_id, context=context) production_ids = production_obj.search(cr, uid, [('move_lines', 'in', [move.id])]) for new_move in new_moves: production_obj.write(cr, uid, production_ids, {'move_lines': [(4, new_move)]}) diff --git a/addons/mrp/mrp_view.xml b/addons/mrp/mrp_view.xml index c1c7a005ccb..d47311f543e 100644 --- a/addons/mrp/mrp_view.xml +++ b/addons/mrp/mrp_view.xml @@ -461,8 +461,6 @@ - -