diff --git a/addons/purchase/data/mail_template_data.xml b/addons/purchase/data/mail_template_data.xml index 35bd59cf12c..f60c96c6d0b 100644 --- a/addons/purchase/data/mail_template_data.xml +++ b/addons/purchase/data/mail_template_data.xml @@ -50,13 +50,9 @@ % endif amounting in ${format_amount(object.amount_total, object.currency_id)} from ${object.company_id.name}. - % if object.date_planned or object.expected_date: - The receipt is planned for - % if object.date_planned: - ${object.date_planned.date()}. - % elif object.expected_date: - ${object.expected_date.date()}. - % endif +

+ % if object.date_planned: + The receipt is expected for ${format_date(object.date_planned)}.

Could you please acknowledge the receipt of this order? % endif @@ -82,13 +78,15 @@ (${object.partner_id.parent_id.name}) % endif

- Here is a reminder that the delivery of the purchase order ${object.name} is planned for + Here is a reminder that the delivery of the purchase order ${object.name} + % if object.partner_ref: + (${object.partner_ref}) + % endif + is expected for % if object.date_planned: - ${object.date_planned.date()}. - % else: - ${object.expected_date.date()}. + ${format_date(object.date_planned)}. % endif - Could you please confirm it will be on time? + Could you please confirm it will be delivered on time?

diff --git a/addons/purchase/data/purchase_data.xml b/addons/purchase/data/purchase_data.xml index fa1af422096..93d6e048a87 100644 --- a/addons/purchase/data/purchase_data.xml +++ b/addons/purchase/data/purchase_data.xml @@ -42,7 +42,7 @@ receipt_reminder_email - + reminder_date_before_receipt diff --git a/addons/purchase/data/purchase_demo.xml b/addons/purchase/data/purchase_demo.xml index 2283fd28778..8f4f80fe21d 100644 --- a/addons/purchase/data/purchase_demo.xml +++ b/addons/purchase/data/purchase_demo.xml @@ -6,6 +6,18 @@ + + True + + + + True + + + + True + + diff --git a/addons/purchase/models/purchase.py b/addons/purchase/models/purchase.py index ff000500ac7..674e09b0daa 100644 --- a/addons/purchase/models/purchase.py +++ b/addons/purchase/models/purchase.py @@ -106,10 +106,8 @@ class PurchaseOrder(models.Model): ('invoiced', 'Fully Billed'), ], string='Billing Status', compute='_get_invoiced', store=True, readonly=True, copy=False, default='no') date_planned = fields.Datetime( - string='Receipt Date', index=True, copy=False, + string='Receipt Date', index=True, copy=False, compute='_compute_date_planned', store=True, readonly=False, help="Delivery date promised by vendor. This date is used to determine expected arrival of products.") - expected_date = fields.Datetime("Expected Date", compute='_compute_expected_date', store=True, - help="Delivery date expected by vendor, computed from the minimum lead time of the order lines.") date_calendar_start = fields.Datetime(compute='_compute_date_calendar_start', readonly=True, store=True) amount_untaxed = fields.Monetary(string='Untaxed Amount', store=True, readonly=True, compute='_amount_all', tracking=True) @@ -130,10 +128,8 @@ class PurchaseOrder(models.Model): mail_reminder_confirmed = fields.Boolean("Reminder Confirmed", default=False, readonly=True, copy=False, help="True if the reminder email is confirmed by the vendor.") mail_reception_confirmed = fields.Boolean("Reception Confirmed", default=False, readonly=True, copy=False, help="True if PO reception is confirmed by the vendor.") - receipt_reminder_email = fields.Boolean('Receipt Reminder Email', related='partner_id.receipt_reminder_email', readonly=False, - help='Automatically send a reminder email to your vendors before receipt') - reminder_date_before_receipt = fields.Integer('Days Before Receipt', related='partner_id.reminder_date_before_receipt', readonly=False, - help="Number of days to send reminder email before the promised receipt date") + receipt_reminder_email = fields.Boolean('Receipt Reminder Email', related='partner_id.receipt_reminder_email', readonly=False) + reminder_date_before_receipt = fields.Integer('Days Before Receipt', related='partner_id.reminder_date_before_receipt', readonly=False) @api.constrains('company_id', 'order_line') def _check_order_line_company_id(self): @@ -168,11 +164,14 @@ class PurchaseOrder(models.Model): order.currency_rate = self.env['res.currency']._get_conversion_rate(order.company_id.currency_id, order.currency_id, order.company_id, order.date_order) @api.depends('order_line.date_planned') - def _compute_expected_date(self): - """ expected_date = the earliest date_planned across all order lines. """ + def _compute_date_planned(self): + """ date_planned = the earliest date_planned across all order lines. """ for order in self: - dates_list = order.order_line.filtered(lambda x: not x.display_type).mapped('date_planned') - order.expected_date = fields.Datetime.to_string(min(dates_list)) if dates_list else False + dates_list = order.order_line.filtered(lambda x: not x.display_type and x.date_planned).mapped('date_planned') + if dates_list: + order.date_planned = fields.Datetime.to_string(min(dates_list)) + else: + order.date_planned = False @api.depends('name', 'partner_ref') def name_get(self): @@ -219,6 +218,17 @@ class PurchaseOrder(models.Model): line.date_planned = line._get_date_planned(seller) return new_po + def onchange(self, values, field_name, field_onchange): + """Override onchange to NOT to update all date_planned on PO lines when + date_planned on PO is updated by the change of date_planned on PO lines. + """ + result = super(PurchaseOrder, self).onchange(values, field_name, field_onchange) + if field_name == 'order_line' and 'value' in result: + for line in result['value'].get('order_line', []): + if line[0] < 2 and 'date_planned' in line[2]: + del line[2]['date_planned'] + return result + def _track_subtype(self, init_values): self.ensure_one() if 'state' in init_values and self.state == 'purchase': @@ -628,23 +638,38 @@ class PurchaseOrder(models.Model): return result - @api.model - def _send_reminder_mail(self): - if not self.user_has_groups('purchase.group_send_reminder') and not self.receipt_reminder_email: + def _send_reminder_mail(self, send_single=False): + if not self.user_has_groups('purchase.group_send_reminder'): return template = self.env.ref('purchase.email_template_edi_purchase_reminder', raise_if_not_found=False) if template: - for order in self._get_orders_to_remind(): - date = order.date_planned or order.expected_date - if date and (date - relativedelta(days=order.reminder_date_before_receipt)).date() == datetime.today().date(): + orders = self if send_single else self._get_orders_to_remind() + for order in orders: + date = order.date_planned + if date and (send_single or (date - relativedelta(days=order.reminder_date_before_receipt)).date() == datetime.today().date()): order.with_context(is_reminder=True).message_post_with_template(template.id, email_layout_xmlid="mail.mail_notification_paynow", composition_mode='comment') + def send_reminder_preview(self): + if not self.user_has_groups('purchase.group_send_reminder') and not self.receipt_reminder_email: + return + + template = self.env.ref('purchase.email_template_edi_purchase_reminder', raise_if_not_found=False) + if template and self.env.user.email: + for order in self: + template.with_context(is_reminder=True).send_mail( + order.id, + force_send=True, + raise_exception=False, + email_values={'email_to': self.env.user.email, 'recipient_ids': []}, + notif_layout="mail.mail_notification_paynow") + @api.model def _get_orders_to_remind(self): """When auto sending a reminder mail, only send for unconfirmed purchase order and not all products are service.""" return self.search([ + ('receipt_reminder_email', '=', True), ('state', 'in', ['purchase', 'done']), ('mail_reminder_confirmed', '=', False) ]).filtered(lambda p: p.mapped('order_line.product_id.product_tmpl_id.type') != ['service']) @@ -655,7 +680,7 @@ class PurchaseOrder(models.Model): if confirm_type in ['reminder', 'reception']: param = url_encode({ 'confirm': confirm_type, - 'confirmed_date': (self.date_planned or self.expected_date).date(), + 'confirmed_date': self.date_planned.date(), }) return self.get_portal_url(query_string='&%s' % param) return self.get_portal_url() @@ -670,7 +695,7 @@ class PurchaseOrder(models.Model): for order in self: if order.state in ['purchase', 'done'] and not order.mail_reminder_confirmed: order.mail_reminder_confirmed = True - date = confirmed_date or (self.date_planned or self.expected_date).date() + date = confirmed_date or self.date_planned.date() order.message_post(body="%s confirmed the receipt will take place on %s." % (order.partner_id.name, date)) def _confirm_reception_mail(self): diff --git a/addons/purchase/models/res_partner.py b/addons/purchase/models/res_partner.py index 69c7bc1be48..c0d75ccbc01 100644 --- a/addons/purchase/models/res_partner.py +++ b/addons/purchase/models/res_partner.py @@ -60,7 +60,7 @@ class res_partner(models.Model): purchase_warn = fields.Selection(WARNING_MESSAGE, 'Purchase Order', help=WARNING_HELP, default="no-message") purchase_warn_msg = fields.Text('Message for Purchase Order') - receipt_reminder_email = fields.Boolean('Receipt Reminder Email', default=True, company_dependent=True, - help='Automatically send a reminder email to your vendors before receipt') + receipt_reminder_email = fields.Boolean('Receipt Reminder', default=False, company_dependent=True, + help="Automatically send a confirmation email to the vendor X days before the expected receipt date, asking him to confirm the exact date.") reminder_date_before_receipt = fields.Integer('Days Before Receipt', default=1, company_dependent=True, help="Number of days to send reminder email before the promised receipt date") diff --git a/addons/purchase/tests/test_purchase.py b/addons/purchase/tests/test_purchase.py index d25436d5562..dae88ecf0d9 100644 --- a/addons/purchase/tests/test_purchase.py +++ b/addons/purchase/tests/test_purchase.py @@ -22,9 +22,9 @@ class TestPurchase(SavepointCase): cls.vendor = cls.env['res.partner'].create({'name': 'vendor1'}) cls.uom_unit = cls.env.ref('uom.product_uom_unit') - def test_expected_date(self): - """Set a date planned on 2 PO lines. Check that the PO expected date is the earliest PO line date - planned. Change one of the dates so it is even earlier and check that the expected date is set to + def test_date_planned(self): + """Set a date planned on 2 PO lines. Check that the PO date_planned is the earliest PO line date + planned. Change one of the dates so it is even earlier and check that the date_planned is set to this earlier date. """ po = Form(self.env['purchase.order']) @@ -42,19 +42,19 @@ class TestPurchase(SavepointCase): # Check that the same date is planned on both PO lines. self.assertNotEqual(po.order_line[0].date_planned, False) self.assertAlmostEqual(po.order_line[0].date_planned, po.order_line[1].date_planned, delta=timedelta(seconds=10)) - self.assertAlmostEqual(po.order_line[0].date_planned, po.expected_date, delta=timedelta(seconds=10)) + self.assertAlmostEqual(po.order_line[0].date_planned, po.date_planned, delta=timedelta(seconds=10)) orig_date_planned = po.order_line[0].date_planned # Set an earlier date planned on a PO line and check that the PO expected date matches it. new_date_planned = orig_date_planned - timedelta(hours=1) po.order_line[0].date_planned = new_date_planned - self.assertAlmostEqual(po.order_line[0].date_planned, po.expected_date, delta=timedelta(seconds=10)) + self.assertAlmostEqual(po.order_line[0].date_planned, po.date_planned, delta=timedelta(seconds=10)) # Set an even earlier date planned on the other PO line and check that the PO expected date matches it. new_date_planned = orig_date_planned - timedelta(hours=72) po.order_line[1].date_planned = new_date_planned - self.assertAlmostEqual(po.order_line[1].date_planned, po.expected_date, delta=timedelta(seconds=10)) + self.assertAlmostEqual(po.order_line[1].date_planned, po.date_planned, delta=timedelta(seconds=10)) def test_purchase_order_sequence(self): PurchaseOrder = self.env['purchase.order'].with_context(tracking_disable=True) diff --git a/addons/purchase/views/purchase_views.xml b/addons/purchase/views/purchase_views.xml index 93982948436..81b7cb68f97 100644 --- a/addons/purchase/views/purchase_views.xml +++ b/addons/purchase/views/purchase_views.xml @@ -143,7 +143,7 @@ - -
- - Ask confirmation - - days before -
+ + {'invisible': [('effective_date', '!=', False)]} - +