diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..dc5e6b6 --- /dev/null +++ b/__init__.py @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from . import models diff --git a/__manifest__.py b/__manifest__.py new file mode 100644 index 0000000..f387343 --- /dev/null +++ b/__manifest__.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + + +{ + 'name': 'POS - Sales Loyality', + 'version': '1.0', + 'category': 'Hidden', + 'sequence': 6, + 'summary': 'Link module between pos_sale and pos_loyalty', + 'description': """ +This module correct some behaviors when both module are installed. +""", + 'depends': ['pos_sale', 'pos_loyalty'], + 'installable': True, + 'auto_install': True, + 'assets': { + 'point_of_sale._assets_pos': [ + 'pos_sale_loyalty/static/src/**/*', + ], + 'web.assets_tests': [ + 'pos_sale_loyalty/static/tests/tours/**/*', + ], + }, + 'license': 'LGPL-3', +} diff --git a/i18n/pos_sale_loyalty.pot b/i18n/pos_sale_loyalty.pot new file mode 100644 index 0000000..b862ea3 --- /dev/null +++ b/i18n/pos_sale_loyalty.pot @@ -0,0 +1,21 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * pos_sale_loyalty +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 17.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2023-10-26 21:55+0000\n" +"PO-Revision-Date: 2023-10-26 21:55+0000\n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: pos_sale_loyalty +#: model:ir.model,name:pos_sale_loyalty.model_sale_order_line +msgid "Sales Order Line" +msgstr "" diff --git a/i18n/ru.po b/i18n/ru.po new file mode 100644 index 0000000..2ec5913 --- /dev/null +++ b/i18n/ru.po @@ -0,0 +1,23 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * pos_sale_loyalty +# +# Translators: +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 17.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2023-10-26 21:55+0000\n" +"PO-Revision-Date: 2024-01-30 15:14+0400\n" +"Last-Translator: \n" +"Language-Team: Russian (https://app.transifex.com/odoo/teams/41243/ru/)\n" +"Language: ru\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);\n" + +#. module: pos_sale_loyalty +#: model:ir.model,name:pos_sale_loyalty.model_sale_order_line +msgid "Sales Order Line" +msgstr "Позиция заказа на продажу" diff --git a/models/__init__.py b/models/__init__.py new file mode 100644 index 0000000..00b62d5 --- /dev/null +++ b/models/__init__.py @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from . import sale_order diff --git a/models/sale_order.py b/models/sale_order.py new file mode 100644 index 0000000..98641fb --- /dev/null +++ b/models/sale_order.py @@ -0,0 +1,13 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import models + + +class SaleOrderLine(models.Model): + _inherit = 'sale.order.line' + + def _get_sale_order_fields(self): + field_names = super()._get_sale_order_fields() + field_names.append('reward_id') + return field_names diff --git a/static/src/overrides/models/models.js b/static/src/overrides/models/models.js new file mode 100644 index 0000000..e2e698f --- /dev/null +++ b/static/src/overrides/models/models.js @@ -0,0 +1,24 @@ +/** @odoo-module **/ + + +import { Orderline } from "@point_of_sale/app/store/models"; +import { patch } from "@web/core/utils/patch"; + +patch(Orderline.prototype, { + //@override + ignoreLoyaltyPoints(args) { + if (this.sale_order_origin_id) { + return true; + } + return super.ignoreLoyaltyPoints(args); + }, + //@override + setQuantityFromSOL(saleOrderLine) { + // we need to consider reward product such as discount in a quotation + if (saleOrderLine.reward_id) { + this.set_quantity(saleOrderLine.product_uom_qty); + } else { + super.setQuantityFromSOL(...arguments); + } + }, +}); diff --git a/static/tests/tours/PosSaleLoyaltyTour.js b/static/tests/tours/PosSaleLoyaltyTour.js new file mode 100644 index 0000000..9cfa002 --- /dev/null +++ b/static/tests/tours/PosSaleLoyaltyTour.js @@ -0,0 +1,25 @@ +/** @odoo-module **/ + +import * as PaymentScreen from "@point_of_sale/../tests/tours/helpers/PaymentScreenTourMethods"; +import * as ReceiptScreen from "@point_of_sale/../tests/tours/helpers/ReceiptScreenTourMethods"; +import * as ProductScreenPos from "@point_of_sale/../tests/tours/helpers/ProductScreenTourMethods"; +import * as ProductScreenSale from "@pos_sale/../tests/helpers/ProductScreenTourMethods"; +const ProductScreen = { ...ProductScreenPos, ...ProductScreenSale }; +import { registry } from "@web/core/registry"; + +registry + .category("web_tour.tours") + .add('PosSaleLoyaltyTour1', { + test: true, + url: '/pos/ui', + steps: () => [ + ProductScreen.confirmOpeningPopup(), + ProductScreen.clickQuotationButton(), + ProductScreen.selectFirstOrder(), + ProductScreen.clickDisplayedProduct('Desk Pad'), + ProductScreen.clickPayButton(), + PaymentScreen.clickPaymentMethod('Bank'), + PaymentScreen.clickValidate(), + ReceiptScreen.isShown(), + ].flat(), + }); diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..a31f197 --- /dev/null +++ b/tests/__init__.py @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from . import test_pos_sale_loyalty diff --git a/tests/test_pos_sale_loyalty.py b/tests/test_pos_sale_loyalty.py new file mode 100644 index 0000000..c6cc67b --- /dev/null +++ b/tests/test_pos_sale_loyalty.py @@ -0,0 +1,45 @@ +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo.addons.point_of_sale.tests.test_frontend import TestPointOfSaleHttpCommon +from odoo.tests import tagged + + +@tagged("post_install", "-at_install") +class TestPoSSaleLoyalty(TestPointOfSaleHttpCommon): + def test_pos_sale_loyalty_1(self): + """Test that only one loyalty card is created when settling an unconfirmed order.""" + self.env['loyalty.program'].search([]).write({'active': False}) + self.env['loyalty.program'].create({ + 'name': 'Test Loyalty Program', + 'program_type': 'loyalty', + 'trigger': 'auto', + 'applies_on': 'both', + 'rule_ids': [ + (0, 0, { + 'reward_point_mode': 'money', + 'minimum_amount': 1, + 'reward_point_amount': 1, + }), + ], + 'reward_ids': [ + (0, 0, { + 'reward_type': 'discount', + 'discount': 1, + 'required_points': 1000, + 'discount_mode': 'percent', + 'discount_applicability': 'order', + }), + ], + }) + self.env['sale.order'].create({ + 'partner_id': self.partner_a.id, + 'order_line': [(0, 0, { + 'product_id': self.desk_organizer.id, + 'product_uom_qty': 1, + 'price_unit': 100, + })] + }) + + self.main_pos_config.open_ui() + self.start_tour("/pos/web?config_id=%d" % self.main_pos_config.id, "PosSaleLoyaltyTour1", login="accountman") + self.assertEqual(self.env['loyalty.card'].search_count([('partner_id', '=', self.partner_a.id)]), 1)