diff --git a/crm_claim_rma/__init__.py b/crm_claim_rma/__init__.py index e879cb2d..cf35d06f 100644 --- a/crm_claim_rma/__init__.py +++ b/crm_claim_rma/__init__.py @@ -2,8 +2,9 @@ ############################################################################## # # Copyright 2013 Camptocamp -# Copyright 2009-2013 Akretion, -# Author: Emmanuel Samyn, Raphaël Valyi, Sébastien Beau, Joel Grand-Guillaume +# Copyright 2009-2013 Akretion, +# Author: Emmanuel Samyn, Raphaël Valyi, Sébastien Beau, +# Joel Grand-Guillaume # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/crm_claim_rma/crm_claim_rma.py b/crm_claim_rma/crm_claim_rma.py index e62d7276..5f9fe4f4 100644 --- a/crm_claim_rma/crm_claim_rma.py +++ b/crm_claim_rma/crm_claim_rma.py @@ -32,6 +32,16 @@ from openerp.tools.translate import _ from openerp import SUPERUSER_ID +class InvoiceNoDate(Exception): + """ Raised when a warranty cannot be computed for a claim line + because the invoice has no date. """ + + +class ProductNoSupplier(Exception): + """ Raised when a warranty cannot be computed for a claim line + because the product has no supplier. """ + + class substate_substate(orm.Model): """ To precise a state (state=refused; substates= reason 1, 2,...) """ _name = "substate.substate" @@ -217,41 +227,57 @@ class claim_line(orm.Model): days = int(days_month * decimal_part) return start + relativedelta(months=months, days=days) - # Method to calculate warranty limit - def set_warranty_limit(self, cr, uid, ids, claim_line, context=None): - date_invoice = claim_line.invoice_line_id.invoice_id.date_invoice + def _warranty_limit_values(self, cr, uid, ids, invoice, + claim_type, product, claim_date, + context=None): + if not (invoice and claim_type and product and claim_date): + return {'guarantee_limit': False, 'warning': False} + date_invoice = invoice.date_invoice if not date_invoice: - raise orm.except_orm( - _('Error'), - _('Cannot find any date for invoice. ' - 'Must be a validated invoice.')) + raise InvoiceNoDate warning = _(self.WARRANT_COMMENT['not_define']) - date_inv_at_server = datetime.strptime(date_invoice, - DEFAULT_SERVER_DATE_FORMAT) - if claim_line.claim_id.claim_type == 'supplier': - suppliers = claim_line.product_id.seller_ids + date_invoice = datetime.strptime(date_invoice, + DEFAULT_SERVER_DATE_FORMAT) + if claim_type == 'supplier': + suppliers = product.seller_ids if not suppliers: - raise orm.except_orm( - _('Error'), - _('The product has no supplier configured.')) + raise ProductNoSupplier supplier = suppliers[0] warranty_duration = supplier.warranty_duration else: - warranty_duration = claim_line.product_id.warranty - limit = self.warranty_limit(date_inv_at_server, warranty_duration) - # If waranty period was defined + warranty_duration = product.warranty + limit = self.warranty_limit(date_invoice, warranty_duration) if warranty_duration > 0: - claim_date = datetime.strptime(claim_line.claim_id.date, + claim_date = datetime.strptime(claim_date, DEFAULT_SERVER_DATETIME_FORMAT) if limit < claim_date: warning = _(self.WARRANT_COMMENT['expired']) else: warning = _(self.WARRANT_COMMENT['valid']) - self.write( - cr, uid, ids, - {'guarantee_limit': limit.strftime(DEFAULT_SERVER_DATE_FORMAT), - 'warning': warning}, - context=context) + return {'guarantee_limit': limit.strftime(DEFAULT_SERVER_DATE_FORMAT), + 'warning': warning} + + def set_warranty_limit(self, cr, uid, ids, claim_line, context=None): + claim = claim_line.claim_id + invoice = claim.invoice_id + claim_type = claim.claim_type + claim_date = claim.date + product = claim_line.product_id + try: + values = self._warranty_limit_values(cr, uid, ids, invoice, + claim_type, product, + claim_date, + context=context) + except InvoiceNoDate: + raise orm.except_orm( + _('Error'), + _('Cannot find any date for invoice. ' + 'Must be a validated invoice.')) + except ProductNoSupplier: + raise orm.except_orm( + _('Error'), + _('The product has no supplier configured.')) + self.write(cr, uid, ids, values, context=context) return True def auto_set_warranty(self, cr, uid, ids, context): @@ -283,9 +309,58 @@ class claim_line(orm.Model): location_dest_id = seller.name.property_stock_supplier.id return location_dest_id - # Method to calculate warranty return address - def set_warranty_return_address(self, cr, uid, ids, claim_line, - context=None): + def onchange_product_id(self, cr, uid, ids, product_id, invoice_line_id, + claim_id, company_id, warehouse_id, + claim_type, claim_date, context=None): + if not claim_id and not (company_id and warehouse_id and + claim_type and claim_date): + # if we have a claim_id, we get the info from there, + # otherwise we get it from the args (on creation typically) + return {} + if not (product_id and invoice_line_id): + return {} + product_obj = self.pool['product.product'] + claim_obj = self.pool['crm.claim'] + invoice_line_obj = self.pool['account.invoice.line'] + claim_line_obj = self.pool.get('claim.line') + product = product_obj.browse(cr, uid, product_id, context=context) + invoice_line = invoice_line_obj.browse(cr, uid, invoice_line_id, + context=context) + invoice = invoice_line.invoice_id + + if claim_id: + claim = claim_obj.browse(cr, uid, claim_id, context=context) + company = claim.company_id + warehouse = claim.warehouse_id + claim_type = claim.claim_type + claim_date = claim.date + else: + warehouse_obj = self.pool['stock.warehouse'] + company_obj = self.pool['res.company'] + company = company_obj.browse(cr, uid, company_id, context=context) + warehouse = warehouse_obj.browse(cr, uid, warehouse_id, + context=context) + + values = {} + try: + warranty = claim_line_obj._warranty_limit_values( + cr, uid, [], invoice, + claim_type, product, + claim_date, context=context) + except (InvoiceNoDate, ProductNoSupplier): + # we don't mind at this point if the warranty can't be + # computed and we don't want to block the user + values.update({'guarantee_limit': False, 'warning': False}) + else: + values.update(warranty) + + warranty_address = claim_line_obj._warranty_return_address_values( + cr, uid, [], product, company, warehouse, context=context) + values.update(warranty_address) + return {'value': values} + + def _warranty_return_address_values(self, cr, uid, ids, product, company, + warehouse, context=None): """Return the partner to be used as return destination and the destination stock location of the line in case of return. @@ -295,28 +370,36 @@ class claim_line(orm.Model): - supplier: return to the supplier address """ + if not (product and company and warehouse): + return {'warranty_return_partner': False, + 'warranty_type': False, + 'location_dest_id': False} return_address = None - seller = claim_line.product_id.seller_info_id + seller = product.seller_info_id if seller: return_address_id = seller.warranty_return_address.id return_type = seller.warranty_return_partner else: # when no supplier is configured, returns to the company - company = claim_line.claim_id.company_id return_address = (company.crm_return_address_id or company.partner_id) return_address_id = return_address.id return_type = 'company' - location_dest_id = self.get_destination_location( - cr, uid, claim_line.product_id.id, - claim_line.claim_id.warehouse_id.id, - context=context) - self.write(cr, uid, ids, - {'warranty_return_partner': return_address_id, - 'warranty_type': return_type, - 'location_dest_id': location_dest_id}, - context=context) + cr, uid, product.id, warehouse.id, context=context) + return {'warranty_return_partner': return_address_id, + 'warranty_type': return_type, + 'location_dest_id': location_dest_id} + + def set_warranty_return_address(self, cr, uid, ids, claim_line, + context=None): + claim = claim_line.claim_id + product = claim_line.product_id + company = claim.company_id + warehouse = claim.warehouse_id + values = self._warranty_return_address_values( + cr, uid, ids, product, company, warehouse, context=context) + self.write(cr, uid, ids, values, context=context) return True def set_warranty(self, cr, uid, ids, context=None): @@ -340,7 +423,8 @@ class crm_claim(orm.Model): def init(self, cr): cr.execute(""" - UPDATE "crm_claim" SET "number"=id::varchar WHERE ("number" is NULL) + UPDATE "crm_claim" SET "number"=id::varchar + WHERE ("number" is NULL) OR ("number" = '/'); """) @@ -457,10 +541,14 @@ class crm_claim(orm.Model): return res def onchange_invoice_id(self, cr, uid, ids, invoice_id, warehouse_id, - context=None): + claim_type, claim_date, company_id, lines, + create_lines=False, context=None): invoice_line_obj = self.pool.get('account.invoice.line') invoice_obj = self.pool.get('account.invoice') + product_obj = self.pool['product.product'] claim_line_obj = self.pool.get('claim.line') + company_obj = self.pool['res.company'] + warehouse_obj = self.pool['stock.warehouse'] invoice_line_ids = invoice_line_obj.search( cr, uid, [('invoice_id', '=', invoice_id)], @@ -472,21 +560,89 @@ class crm_claim(orm.Model): context=context) invoice_lines = invoice_line_obj.browse(cr, uid, invoice_line_ids, context=context) - for invoice_line in invoice_lines: - product_id = invoice_line.product_id and invoice_line.product_id.id or False - location_dest_id = claim_line_obj.get_destination_location( - cr, uid, product_id, - warehouse_id, context=context) - claim_lines.append({ - 'name': invoice_line.name, - 'claim_origine': "none", - 'invoice_line_id': invoice_line.id, - 'product_id': product_id, - 'product_returned_quantity': invoice_line.quantity, - 'unit_sale_price': invoice_line.price_unit, - 'location_dest_id': location_dest_id, - 'state': 'draft', - }) + + def warranty_values(invoice, product): + values = {} + try: + warranty = claim_line_obj._warranty_limit_values( + cr, uid, [], invoice, + claim_type, product, + claim_date, context=context) + except (InvoiceNoDate, ProductNoSupplier): + # we don't mind at this point if the warranty can't be + # computed and we don't want to block the user + values.update({'guarantee_limit': False, 'warning': False}) + else: + values.update(warranty) + company = company_obj.browse(cr, uid, company_id, context=context) + warehouse = warehouse_obj.browse(cr, uid, warehouse_id, + context=context) + warranty_address = claim_line_obj._warranty_return_address_values( + cr, uid, [], product, company, + warehouse, context=context) + values.update(warranty_address) + return values + + if create_lines: # happens when the invoice is changed + for invoice_line in invoice_lines: + location_dest_id = claim_line_obj.get_destination_location( + cr, uid, invoice_line.product_id.id, + warehouse_id, context=context) + line = { + 'name': invoice_line.name, + 'claim_origine': "none", + 'invoice_line_id': invoice_line.id, + 'product_id': invoice_line.product_id.id, + 'product_returned_quantity': invoice_line.quantity, + 'unit_sale_price': invoice_line.price_unit, + 'location_dest_id': location_dest_id, + 'state': 'draft', + } + line.update(warranty_values(invoice_line.invoice_id, + invoice_line.product_id)) + claim_lines.append(line) + elif lines: # happens when the date, warehouse or claim type is + # modified + for command in lines: + code = command[0] + assert code != 6, "command 6 not supported in on_change" + if code in (0, 1, 4): + # 0: link a new record with values + # 1: update an existing record with values + # 4: link to existing record + line_id = command[1] + if code == 4: + code = 1 # we want now to update values + values = {} + else: + values = command[2] + invoice_line_id = values.get('invoice_line_id') + product_id = values.get('product_id') + if code == 1: # get the existing line + # if the fields have not changed, fallback + # on the database values + browse_line = claim_line_obj.read(cr, uid, + line_id, + ['invoice_line_id', + 'product_id'], + context=context) + if not invoice_line_id: + invoice_line_id = browse_line['invoice_line_id'][0] + if not product_id: + product_id = browse_line['product_id'][0] + + if invoice_line_id and product_id: + invoice_line = invoice_line_obj.browse(cr, uid, + invoice_line_id, + context=context) + product = product_obj.browse(cr, uid, product_id, + context=context) + values.update(warranty_values(invoice_line.invoice_id, + product)) + claim_lines.append((code, line_id, values)) + elif code in (2, 3, 5): + claim_lines.append(command) + value = {'claim_line_ids': claim_lines} delivery_address_id = False if invoice_id: diff --git a/crm_claim_rma/crm_claim_rma_view.xml b/crm_claim_rma/crm_claim_rma_view.xml index 4567dbbc..65f4dc29 100644 --- a/crm_claim_rma/crm_claim_rma_view.xml +++ b/crm_claim_rma/crm_claim_rma_view.xml @@ -92,14 +92,16 @@ - + - + @@ -165,13 +167,63 @@ - + + - + +
+
+
+ +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
@@ -264,8 +316,8 @@ - - + +
@@ -277,7 +329,7 @@ - +
diff --git a/crm_claim_rma/tests/test_lp_1282584.py b/crm_claim_rma/tests/test_lp_1282584.py index c3cd36ff..d9e21500 100644 --- a/crm_claim_rma/tests/test_lp_1282584.py +++ b/crm_claim_rma/tests/test_lp_1282584.py @@ -78,7 +78,8 @@ class test_lp_1282584(common.TransactionCase): res = self.WizardMakePicking.action_create_picking( cr, uid, [wizard_id], context=wiz_context) - self.assertEquals(res.get('res_model'), 'stock.picking.in', "Wrong model defined") + self.assertEquals(res.get('res_model'), 'stock.picking.in', + "Wrong model defined") def test_01(self): """Test wizard opened view model for a new delivery @@ -92,7 +93,9 @@ class test_lp_1282584(common.TransactionCase): wizard_chg_qty_id = WizardChangeProductQty.create(cr, uid, { 'product_id': self.product_id, 'new_quantity': 12}) - WizardChangeProductQty.change_product_qty(cr, uid, [wizard_chg_qty_id], context=wiz_context) + WizardChangeProductQty.change_product_qty(cr, uid, + [wizard_chg_qty_id], + context=wiz_context) wiz_context = { 'active_id': self.claim_id, @@ -105,4 +108,5 @@ class test_lp_1282584(common.TransactionCase): res = self.WizardMakePicking.action_create_picking( cr, uid, [wizard_id], context=wiz_context) - self.assertEquals(res.get('res_model'), 'stock.picking.out', "Wrong model defined") + self.assertEquals(res.get('res_model'), 'stock.picking.out', + "Wrong model defined") diff --git a/crm_claim_rma/wizard/claim_make_picking.py b/crm_claim_rma/wizard/claim_make_picking.py index fb97602a..3acd8faa 100644 --- a/crm_claim_rma/wizard/claim_make_picking.py +++ b/crm_claim_rma/wizard/claim_make_picking.py @@ -223,14 +223,15 @@ class claim_make_picking(orm.TransientModel): }, context=context) # Create picking lines + fmt = DEFAULT_SERVER_DATETIME_FORMAT for wizard_claim_line in wizard.claim_line_ids: move_obj = self.pool.get('stock.move') move_id = move_obj.create( cr, uid, {'name': wizard_claim_line.product_id.name_template, 'priority': '0', - 'date': time.strftime(DEFAULT_SERVER_DATETIME_FORMAT), - 'date_expected': time.strftime(DEFAULT_SERVER_DATETIME_FORMAT), + 'date': time.strftime(fmt), + 'date_expected': time.strftime(fmt), 'product_id': wizard_claim_line.product_id.id, 'product_qty': wizard_claim_line.product_returned_quantity, 'product_uom': wizard_claim_line.product_id.uom_id.id,