diff --git a/modules/sale_complaint/CHANGELOG b/modules/sale_complaint/CHANGELOG index 1b532557b4..6a491926ed 100644 --- a/modules/sale_complaint/CHANGELOG +++ b/modules/sale_complaint/CHANGELOG @@ -1,3 +1,4 @@ +* Add promotion coupon as action * Use actual quantity of sale line Version 7.4.0 - 2024-11-04 diff --git a/modules/sale_complaint/__init__.py b/modules/sale_complaint/__init__.py index 392364bbc2..804f54fc02 100644 --- a/modules/sale_complaint/__init__.py +++ b/modules/sale_complaint/__init__.py @@ -18,3 +18,8 @@ def register(): sale.Sale, account.InvoiceLine, module='sale_complaint', type_='model') + Pool.register( + complaint.Complaint_PromotionCoupon, + complaint.Action_PromotionCoupon, + module='sale_complaint', type_='model', + depends=['sale_promotion_coupon']) diff --git a/modules/sale_complaint/complaint.py b/modules/sale_complaint/complaint.py index f392c53265..b30166f403 100644 --- a/modules/sale_complaint/complaint.py +++ b/modules/sale_complaint/complaint.py @@ -1,6 +1,7 @@ # This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. +import datetime as dt from collections import defaultdict from decimal import Decimal @@ -15,7 +16,7 @@ from trytond.modules.company.model import ( employee_field, reset_employee, set_employee) from trytond.modules.currency.fields import Monetary from trytond.modules.product import price_digits -from trytond.pool import Pool +from trytond.pool import Pool, PoolMeta from trytond.pyson import Bool, Eval, If from trytond.tools import grouped_slice from trytond.transaction import Transaction @@ -497,6 +498,9 @@ class Action(ModelSQL, ModelView): complaint_state = fields.Function( fields.Selection('get_complaint_states', "Complaint State"), 'on_change_with_complaint_state') + company = fields.Function( + fields.Many2One('company.company', "Company"), + 'on_change_with_company') @classmethod def __setup__(cls): @@ -583,6 +587,11 @@ class Action(ModelSQL, ModelView): if self.complaint: return self.complaint.state + @fields.depends('complaint', '_parent_complaint.company') + def on_change_with_company(self, name=None): + if self.complaint: + return self.complaint.company + @classmethod def _get_result(cls): 'Return list of Model names for result Reference' @@ -861,3 +870,67 @@ class Action_InvoiceLine(_Action_Line, ModelView, ModelSQL): return self.unit_price elif self.line: return self.line.unit_price + + +class Complaint_PromotionCoupon(metaclass=PoolMeta): + __name__ = 'sale.complaint' + + @classmethod + def _actions_domains(cls): + domains = super()._actions_domains() + for name, domain in domains.items(): + domain.append('promotion_coupon') + return domains + + +class Action_PromotionCoupon(metaclass=PoolMeta): + __name__ = 'sale.complaint.action' + + _promtion_coupon_states = { + 'invisible': Eval('action') != 'promotion_coupon', + 'required': Eval('action') == 'promotion_coupon', + } + + promotion_coupon = fields.Many2One( + 'sale.promotion.coupon', "Promotion Coupon", + domain=[ + ('company', '=', Eval('company', -1)), + ('number_of_use', '=', 1), + ('per_party', '=', False), + ], + states=_promtion_coupon_states) + promotion_coupon_number = fields.Char( + "Number", states=_promtion_coupon_states) + promotion_coupon_duration = fields.TimeDelta( + "Duration", states=_promtion_coupon_states) + + del _promtion_coupon_states + + @classmethod + def __setup__(cls): + super().__setup__() + cls.action.selection.append(('promotion_coupon', "Promotion Coupon")) + + @classmethod + def default_promotion_coupon_duration(cls): + return dt.timedelta(days=90) + + @classmethod + def _get_result(cls): + return super()._get_result() + ['sale.promotion.coupon.number'] + + def do_promotion_coupon(self): + pool = Pool() + PromotionCouponNumber = pool.get('sale.promotion.coupon.number') + Date = pool.get('ir.date') + + with Transaction().set_context(company=self.company.id): + today = Date.today() + + return PromotionCouponNumber( + number=self.promotion_coupon_number, + coupon=self.promotion_coupon, + company=self.company, + start_date=today, + end_date=today + self.promotion_coupon_duration, + ) diff --git a/modules/sale_complaint/complaint.xml b/modules/sale_complaint/complaint.xml index 9aae795aa8..268e9ddfb1 100644 --- a/modules/sale_complaint/complaint.xml +++ b/modules/sale_complaint/complaint.xml @@ -288,4 +288,11 @@ this repository contains the full copyright notices and license terms. --> action_line_list + + + sale.complaint.action + + action_form_promotion_coupon + + diff --git a/modules/sale_complaint/setup.py b/modules/sale_complaint/setup.py index ed092ac844..02c3f4d8d3 100755 --- a/modules/sale_complaint/setup.py +++ b/modules/sale_complaint/setup.py @@ -47,7 +47,10 @@ for dep in info.get('depends', []): requires.append(get_require_version('trytond_%s' % dep)) requires.append(get_require_version('trytond')) -tests_require = [get_require_version('proteus')] +tests_require = [ + get_require_version('proteus'), + get_require_version('trytond_sale_promotion_coupon'), + ] setup(name=name, version=version, diff --git a/modules/sale_complaint/tests/scenario_sale_complaint_promotion_coupon.rst b/modules/sale_complaint/tests/scenario_sale_complaint_promotion_coupon.rst new file mode 100644 index 0000000000..50f8b90114 --- /dev/null +++ b/modules/sale_complaint/tests/scenario_sale_complaint_promotion_coupon.rst @@ -0,0 +1,122 @@ +============================================= +Sale Complaint with Promotion Coupon Scenario +============================================= + +Imports:: + + >>> import datetime as dt + >>> from decimal import Decimal + + >>> from proteus import Model + >>> from trytond.modules.account.tests.tools import ( + ... create_chart, create_fiscalyear, get_accounts) + >>> from trytond.modules.account_invoice.tests.tools import ( + ... set_fiscalyear_invoice_sequences) + >>> from trytond.modules.company.tests.tools import create_company + >>> from trytond.tests.tools import activate_modules, assertEqual + +Activate modules:: + + >>> config = activate_modules( + ... ['sale_complaint', 'sale_promotion_coupon'], + ... create_company, create_chart) + + >>> Complaint = Model.get('sale.complaint') + >>> IrModel = Model.get('ir.model') + >>> Party = Model.get('party.party') + >>> ProductCategory = Model.get('product.category') + >>> ProductTemplate = Model.get('product.template') + >>> ProductUom = Model.get('product.uom') + >>> Promotion = Model.get('sale.promotion') + >>> Sale = Model.get('sale.sale') + >>> Type = Model.get('sale.complaint.type') + +Create fiscal year:: + + >>> fiscalyear = set_fiscalyear_invoice_sequences(create_fiscalyear()) + >>> fiscalyear.click('create_period') + +Get accounts:: + + >>> accounts = get_accounts() + +Create parties:: + + >>> customer = Party(name='Customer') + >>> customer.save() + +Create complaint type:: + + >>> sale_type = Type(name='Sale') + >>> sale_type.origin, = IrModel.find([('name', '=', 'sale.sale')]) + >>> sale_type.save() + +Create account category:: + + >>> account_category = ProductCategory(name="Account Category") + >>> account_category.accounting = True + >>> account_category.account_revenue = accounts['revenue'] + >>> account_category.save() + +Create product:: + + >>> unit, = ProductUom.find([('name', '=', "Unit")]) + + >>> template = ProductTemplate() + >>> template.name = "Product" + >>> template.default_uom = unit + >>> template.type = 'goods' + >>> template.salable = True + >>> template.list_price = Decimal('10') + >>> template.account_category = account_category + >>> template.save() + >>> product, = template.products + +Create Promotion with coupon:: + + >>> promotion = Promotion(name="50%") + >>> promotion.formula = '0.5 * unit_price' + >>> coupon = promotion.coupons.new() + >>> coupon.number_of_use = 1 + >>> coupon.per_party = False + >>> promotion.save() + >>> coupon, = promotion.coupons + +Sale 1 product:: + + >>> sale = Sale() + >>> sale.party = customer + >>> sale_line = sale.lines.new() + >>> sale_line.product = product + >>> sale_line.quantity = 1 + >>> sale.click('quote') + >>> sale.click('confirm') + >>> sale.state + 'processing' + +Fill a complaint for the sale:: + + >>> complaint = Complaint() + >>> complaint.customer = customer + >>> complaint.type = sale_type + >>> complaint.origin = sale + >>> complaint.save() + +Resolve complaint with a coupon:: + + >>> action = complaint.actions.new(action='promotion_coupon') + >>> action.promotion_coupon = coupon + >>> action.promotion_coupon_number = "DISC50" + >>> action.promotion_coupon_duration = dt.timedelta(days=30) + >>> complaint.click('wait') + >>> complaint.click('approve') + >>> complaint.state + 'done' + + >>> action, = complaint.actions + >>> coupon_number = action.result + >>> coupon_number.number + 'DISC50' + >>> assertEqual(coupon_number.coupon, coupon) + >>> assertEqual( + ... coupon_number.end_date - coupon_number.start_date, dt.timedelta(days=30)) diff --git a/modules/sale_complaint/tests/test_module.py b/modules/sale_complaint/tests/test_module.py index 065167079e..357898ef2d 100644 --- a/modules/sale_complaint/tests/test_module.py +++ b/modules/sale_complaint/tests/test_module.py @@ -8,6 +8,7 @@ from trytond.tests.test_tryton import ModuleTestCase class SaleComplaintTestCase(CompanyTestMixin, ModuleTestCase): 'Test Sale Complaint module' module = 'sale_complaint' + extras = ['sale_promotion_coupon'] del ModuleTestCase diff --git a/modules/sale_complaint/tryton.cfg b/modules/sale_complaint/tryton.cfg index 14a842de9f..67c157aff6 100644 --- a/modules/sale_complaint/tryton.cfg +++ b/modules/sale_complaint/tryton.cfg @@ -6,6 +6,8 @@ depends: ir party sale +extras_depend: + sale_promotion_coupon xml: complaint.xml sale.xml diff --git a/modules/sale_complaint/view/action_form_promotion_coupon.xml b/modules/sale_complaint/view/action_form_promotion_coupon.xml new file mode 100644 index 0000000000..3a37827202 --- /dev/null +++ b/modules/sale_complaint/view/action_form_promotion_coupon.xml @@ -0,0 +1,15 @@ + + + + + +