# -*- coding: utf-8 -*- import datetime from odoo.addons.sale.tests.common import TestSaleCommon from odoo import Command class TestSubscriptionCommon(TestSaleCommon): def setUp(self): super(TestSubscriptionCommon, self).setUp() SO = type(self.env['sale.order']) def _subscription_launch_cron_single(self, batch_size): self.env['sale.order']._create_recurring_invoice(batch_size=batch_size) self.patch(SO, '_subscription_launch_cron_parallel', _subscription_launch_cron_single) @classmethod def setUpClass(cls, chart_template_ref=None): super().setUpClass(chart_template_ref=chart_template_ref) cls.env.ref('base.main_company').currency_id = cls.env.ref('base.USD') # disable most emails for speed context_no_mail = {'no_reset_password': True, 'mail_create_nosubscribe': True, 'mail_create_nolog': True} AnalyticPlan = cls.env['account.analytic.plan'].with_context(context_no_mail) Analytic = cls.env['account.analytic.account'].with_context(context_no_mail) SaleOrder = cls.env['sale.order'].with_context(context_no_mail) SubPlan = cls.env['sale.subscription.plan'].with_context(context_no_mail) SubPricing = cls.env['sale.subscription.pricing'].with_context(context_no_mail) Tax = cls.env['account.tax'].with_context(context_no_mail) ProductTmpl = cls.env['product.template'].with_context(context_no_mail) cls.country_belgium = cls.env.ref('base.be') # Minimal CoA & taxes setup cls.account_payable = cls.company_data['default_account_payable'] cls.account_receivable = cls.company_data['default_account_receivable'] cls.account_income = cls.company_data['default_account_revenue'] cls.company_data['company'].deferred_journal_id = cls.company_data['default_journal_misc'].id cls.company_data['company'].deferred_expense_account_id = cls.company_data['default_account_deferred_expense'].id cls.company_data['company'].deferred_revenue_account_id = cls.company_data['default_account_deferred_revenue'].id cls.tax_10 = Tax.create({ 'name': "10% tax", 'amount_type': 'percent', 'amount': 10, }) cls.tax_20 = Tax.create({ 'name': "20% tax", 'amount_type': 'percent', 'amount': 20, }) cls.journal = cls.company_data['default_journal_sale'] # Test products cls.plan_week = SubPlan.create({'name': 'Weekly', 'billing_period_value': 1, 'billing_period_unit': 'week'}) cls.plan_month = SubPlan.create({'name': 'Monthly', 'billing_period_value': 1, 'billing_period_unit': 'month'}) cls.plan_year = SubPlan.create({'name': 'Yearly', 'billing_period_value': 1, 'billing_period_unit': 'year'}) cls.plan_2_month = SubPlan.create({'name': '2 Months', 'billing_period_value': 2, 'billing_period_unit': 'month'}) cls.pricing_month = SubPricing.create({'plan_id': cls.plan_month.id, 'price': 1}) cls.pricing_year = SubPricing.create({'plan_id': cls.plan_year.id, 'price': 100}) cls.pricing_year_2 = SubPricing.create({'plan_id': cls.plan_year.id, 'price': 200}) cls.pricing_year_3 = SubPricing.create({'plan_id': cls.plan_year.id, 'price': 300}) cls.sub_product_tmpl = ProductTmpl.create({ 'name': 'BaseTestProduct', 'type': 'service', 'recurring_invoice': True, 'uom_id': cls.env.ref('uom.product_uom_unit').id, 'product_subscription_pricing_ids': [(6, 0, (cls.pricing_month | cls.pricing_year).ids)] }) cls.product = cls.sub_product_tmpl.product_variant_id cls.product.write({ 'list_price': 50.0, 'taxes_id': [(6, 0, [cls.tax_10.id])], 'property_account_income_id': cls.account_income.id, }) cls.product_tmpl_2 = ProductTmpl.create({ 'name': 'TestProduct2', 'type': 'service', 'recurring_invoice': True, 'uom_id': cls.env.ref('uom.product_uom_unit').id, }) cls.product2 = cls.product_tmpl_2.product_variant_id cls.product2.write({ 'list_price': 20.0, 'taxes_id': [(6, 0, [cls.tax_10.id])], 'property_account_income_id': cls.account_income.id, }) cls.product_tmpl_3 = ProductTmpl.create({ 'name': 'TestProduct3', 'type': 'service', 'recurring_invoice': True, 'uom_id': cls.env.ref('uom.product_uom_unit').id, }) cls.product3 = cls.product_tmpl_3.product_variant_id cls.product3.write({ 'list_price': 15.0, 'taxes_id': [(6, 0, [cls.tax_10.id])], 'property_account_income_id': cls.account_income.id, }) cls.product_tmpl_4 = ProductTmpl.create({ 'name': 'TestProduct4', 'type': 'service', 'recurring_invoice': True, 'uom_id': cls.env.ref('uom.product_uom_unit').id, }) cls.product4 = cls.product_tmpl_4.product_variant_id cls.product4.write({ 'list_price': 15.0, 'taxes_id': [(6, 0, [cls.tax_20.id])], 'property_account_income_id': cls.account_income.id, }) cls.product_tmpl_5 = ProductTmpl.create({ 'name': 'One shot product', 'type': 'service', 'recurring_invoice': False, 'uom_id': cls.env.ref('uom.product_uom_unit').id, }) cls.product5 = cls.product_tmpl_3.product_variant_id cls.product5.write({ 'list_price': 42.0, 'taxes_id': [(6, 0, [cls.tax_10.id])], 'property_account_income_id': cls.account_income.id, }) cls.subscription_tmpl = cls.env['sale.order.template'].create({ 'name': 'Subscription template without discount', 'is_unlimited': False, 'duration_value': 2, 'duration_unit': 'year', 'note': "This is the template description", 'plan_id': cls.plan_month.id, 'sale_order_template_line_ids': [Command.create({ 'name': "Product 1", 'product_id': cls.product.id, 'product_uom_qty': 1, 'product_uom_id': cls.product.uom_id.id }), Command.create({ 'name': "Product 2", 'product_id': cls.product2.id, 'product_uom_qty': 1, 'product_uom_id': cls.product2.uom_id.id, }) ] }) cls.templ_5_days = cls.env['sale.order.template'].create({ 'name': 'Template 2 days', 'is_unlimited': False, 'note': "This is the template description", 'duration_value': 4, 'duration_unit': 'year', 'plan_id': cls.plan_year.copy(default={'auto_close_limit': 5}).id, 'sale_order_template_line_ids': [ (0, 0, { 'name': cls.product.name, 'product_id': cls.product.id, 'product_uom_qty': 3.0, 'product_uom_id': cls.product.uom_id.id, }), (0, 0, { 'name': cls.product2.name, 'product_id': cls.product2.id, 'product_uom_qty': 2.0, 'product_uom_id': cls.product2.uom_id.id, }) ], }) cls.templ_60_days = cls.templ_5_days.copy() cls.templ_60_days.plan_id = cls.plan_year.copy(default={'auto_close_limit': 60}) # Test user TestUsersEnv = cls.env['res.users'].with_context({'no_reset_password': True}) group_portal_id = cls.env.ref('base.group_portal').id cls.country_belgium = cls.env.ref('base.be') cls.user_portal = TestUsersEnv.create({ 'name': 'Beatrice Portal', 'login': 'Beatrice', 'country_id': cls.country_belgium.id, 'email': 'beatrice.employee@example.com', 'groups_id': [(6, 0, [group_portal_id])], 'property_account_payable_id': cls.account_payable.id, 'property_account_receivable_id': cls.account_receivable.id, 'company_id': cls.company_data['company'].id, }) cls.malicious_user = TestUsersEnv.create({ 'name': 'Al Capone', 'login': 'al', 'password': 'alalalal', 'email': 'al@capone.it', 'groups_id': [(6, 0, [group_portal_id])], 'property_account_receivable_id': cls.account_receivable.id, 'property_account_payable_id': cls.account_receivable.id, }) cls.legit_user = TestUsersEnv.create({ 'name': 'Eliot Ness', 'login': 'ness', 'password': 'nessnessness', 'email': 'ness@USDT.us', 'groups_id': [(6, 0, [group_portal_id])], 'property_account_receivable_id': cls.account_receivable.id, 'property_account_payable_id': cls.account_receivable.id, }) # Test analytic account cls.plan_1 = AnalyticPlan.create({ 'name': 'Test Plan 1', }) cls.account_1 = Analytic.create({ 'partner_id': cls.user_portal.partner_id.id, 'name': 'Test Account 1', 'plan_id': cls.plan_1.id, }) cls.account_2 = Analytic.create({ 'partner_id': cls.user_portal.partner_id.id, 'name': 'Test Account 2', 'plan_id': cls.plan_1.id, }) # Test Subscription cls.subscription = SaleOrder.create({ 'name': 'TestSubscription', 'is_subscription': True, 'plan_id': cls.plan_month.id, 'note': "original subscription description", 'partner_id': cls.user_portal.partner_id.id, 'pricelist_id': cls.company_data['default_pricelist'].id, 'sale_order_template_id': cls.subscription_tmpl.id, }) cls.subscription._onchange_sale_order_template_id() cls.subscription.start_date = False # the confirmation will set the start_date cls.subscription.end_date = False # reset the end_date too cls.company = cls.env.company cls.company.country_id = cls.env.ref('base.us') cls.account_receivable = cls.env['account.account'].create( {'name': 'Ian Anderson', 'code': 'IA', 'account_type': 'asset_receivable', 'company_id': cls.company.id, 'reconcile': True}) cls.account_sale = cls.env['account.account'].create( {'name': 'Product Sales ', 'code': 'S200000', 'account_type': 'income', 'company_id': cls.company.id, 'reconcile': False}) cls.sale_journal = cls.env['account.journal'].create( {'name': 'reflets.info', 'code': 'ref', 'type': 'sale', 'company_id': cls.company.id, 'default_account_id': cls.account_sale.id}) belgium = cls.env.ref('base.be') cls.partner = cls.env['res.partner'].create( {'name': 'Stevie Nicks', 'email': 'sti@fleetwood.mac', 'country_id': belgium.id, 'property_account_receivable_id': cls.account_receivable.id, 'property_account_payable_id': cls.account_receivable.id, 'company_id': cls.company.id}) cls.provider = cls.env['payment.provider'].create( {'name': 'The Wire', 'company_id': cls.company.id, 'state': 'test', 'redirect_form_view_id': cls.env['ir.ui.view'].search([('type', '=', 'qweb')], limit=1).id}) cls.payment_method_id = cls.env.ref('payment.payment_method_unknown').id cls.payment_token = cls.env['payment.token'].create( {'payment_details': 'Jimmy McNulty', 'partner_id': cls.partner.id, 'provider_id': cls.provider.id, 'payment_method_id': cls.payment_method_id, 'provider_ref': 'Omar Little'}) Partner = cls.env['res.partner'] cls.partner_a_invoice = Partner.create({ 'parent_id': cls.partner_a.id, 'type': 'invoice', }) cls.partner_a_shipping = Partner.create({ 'parent_id': cls.partner_a.id, 'type': 'delivery', }) cls.mock_send_success_count = 0 # Mocking for 'test_auto_payment_with_token' # Necessary to have a valid and done transaction when the cron on subscription passes through def _mock_subscription_do_payment(self, payment_token, invoice, auto_commit=False): tx_obj = self.env['payment.transaction'] refs = invoice.invoice_line_ids.sale_line_ids.order_id.mapped('client_order_ref') ref_vals = [r for r in refs if r] reference = "CONTRACT-%s-%s-%s" % (invoice.id, ''.join(ref_vals), datetime.datetime.now().strftime('%y%m%d_%H%M%S%f')) provider = invoice.env.context.get('test_provider', self.provider) values = [{ 'amount': invoice.amount_total, 'provider_id': provider.id, 'payment_method_id': self.payment_method_id, 'operation': 'offline', 'currency_id': invoice.currency_id.id, 'reference': reference, 'token_id': payment_token.id, 'partner_id': invoice.partner_id.id, 'partner_country_id': invoice.partner_id.country_id.id, 'sale_order_ids': [(6, 0, invoice.invoice_line_ids.sale_line_ids.order_id.ids)], 'invoice_ids': [(6, 0, [invoice.id])], 'state': 'done', 'subscription_action': 'automatic_send_mail', }] tx = tx_obj.create(values) return tx def _mock_subscription_do_payment_rejected(self, payment_method, invoice, auto_commit=False): tx = self._mock_subscription_do_payment(payment_method, invoice) tx.state = "pending" tx._set_error("Payment declined") tx.env.cr.flush() # simulate commit after sucessfull `_do_payment()` return tx def _mock_subscription_do_payment_pending(self, payment_method, invoice, auto_commit=False): tx = self._mock_subscription_do_payment(payment_method, invoice) tx.state = "pending" tx.env.cr.flush() # simulate commit after sucessfull `_do_payment()` return tx # Mocking for 'test_auto_payment_with_token' # Otherwise the whole sending mail process will be triggered # And we are not here to test that flow, and it is a heavy one def _mock_subscription_send_success_mail(self, tx, invoice): self.mock_send_success_count += 1 return 666 # Mocking for 'test_auto_payment_with_token' # Avoid account_id is False when creating the invoice def _mock_prepare_invoice_data(self): invoice = self.original_prepare_invoice() invoice['partner_bank_id'] = False return invoice def flush_tracking(self): self.env.flush_all() self.cr.flush()