mirror of
https://github.com/bringout/oca-ocb-l10n_asia-pacific.git
synced 2026-04-25 16:02:04 +02:00
19.0 vanilla
This commit is contained in:
parent
7dc55599c6
commit
7f43bbbfcc
650 changed files with 45260 additions and 33436 deletions
|
|
@ -10,38 +10,15 @@ pip install odoo-bringout-oca-ocb-l10n_in_pos
|
|||
|
||||
## Dependencies
|
||||
|
||||
This addon depends on:
|
||||
- l10n_in
|
||||
- point_of_sale
|
||||
|
||||
## Manifest Information
|
||||
|
||||
- **Name**: Indian - Point of Sale
|
||||
- **Version**: 1.0
|
||||
- **Category**: Accounting/Localizations/Point of Sale
|
||||
- **License**: LGPL-3
|
||||
- **Installable**: False
|
||||
|
||||
## Source
|
||||
|
||||
Based on [OCA/OCB](https://github.com/OCA/OCB) branch 16.0, addon `l10n_in_pos`.
|
||||
- Repository: https://github.com/OCA/OCB
|
||||
- Branch: 19.0
|
||||
- Path: addons/l10n_in_pos
|
||||
|
||||
## License
|
||||
|
||||
This package maintains the original LGPL-3 license from the upstream Odoo project.
|
||||
|
||||
## Documentation
|
||||
|
||||
- Overview: doc/OVERVIEW.md
|
||||
- Architecture: doc/ARCHITECTURE.md
|
||||
- Models: doc/MODELS.md
|
||||
- Controllers: doc/CONTROLLERS.md
|
||||
- Wizards: doc/WIZARDS.md
|
||||
- Reports: doc/REPORTS.md
|
||||
- Security: doc/SECURITY.md
|
||||
- Install: doc/INSTALL.md
|
||||
- Usage: doc/USAGE.md
|
||||
- Configuration: doc/CONFIGURATION.md
|
||||
- Dependencies: doc/DEPENDENCIES.md
|
||||
- Troubleshooting: doc/TROUBLESHOOTING.md
|
||||
- FAQ: doc/FAQ.md
|
||||
This package preserves the original LGPL-3 license.
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
|
||||
{
|
||||
'name': 'Indian - Point of Sale',
|
||||
'icon': '/l10n_in/static/description/icon.png',
|
||||
'version': '1.0',
|
||||
'description': """GST Point of Sale""",
|
||||
'category': 'Accounting/Localizations/Point of Sale',
|
||||
|
|
@ -11,15 +10,25 @@
|
|||
'l10n_in',
|
||||
'point_of_sale'
|
||||
],
|
||||
'data': [
|
||||
'views/pos_order_line_views.xml',
|
||||
'views/product_view.xml',
|
||||
'views/res_config_settings_views.xml',
|
||||
'data/pos_bill_data.xml',
|
||||
],
|
||||
'demo': [
|
||||
'data/product_demo.xml',
|
||||
],
|
||||
'auto_install': True,
|
||||
'assets': {
|
||||
'point_of_sale.assets': [
|
||||
'l10n_in_pos/static/src/js/**/*',
|
||||
'l10n_in_pos/static/src/xml/**/*',
|
||||
'point_of_sale._assets_pos': [
|
||||
'l10n_in/static/src/helpers/hsn_summary.js',
|
||||
'l10n_in_pos/static/src/**/*',
|
||||
],
|
||||
'web.assets_tests': [
|
||||
'l10n_in_pos/static/tests/tours/**/*',
|
||||
],
|
||||
},
|
||||
'author': 'Odoo S.A.',
|
||||
'license': 'LGPL-3',
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
<odoo>
|
||||
<data noupdate="1">
|
||||
<record model="pos.bill" id="500_00" forcecreate="0">
|
||||
<field name="name">500.00</field>
|
||||
<field name="value">500.00</field>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
|
|
@ -1,57 +1,40 @@
|
|||
<odoo>
|
||||
<data noupdate="1">
|
||||
<record id="point_of_sale.desk_organizer" model="product.product">
|
||||
<record id="product.desk_organizer" model="product.product">
|
||||
<field name="l10n_in_hsn_code">9403</field>
|
||||
<field name="l10n_in_hsn_description">Other furniture and parts thereof.</field>
|
||||
</record>
|
||||
<record id="point_of_sale.desk_pad" model="product.product">
|
||||
<record id="product.desk_pad" model="product.product">
|
||||
<field name="l10n_in_hsn_code">9403</field>
|
||||
<field name="l10n_in_hsn_description">Other furniture and parts thereof.</field>
|
||||
</record>
|
||||
<record id="point_of_sale.led_lamp" model="product.product">
|
||||
<field name="l10n_in_hsn_code">8539.50.00</field>
|
||||
<field name="l10n_in_hsn_description">Light-emitting diode (LED) lamps</field>
|
||||
<field name="l10n_in_hsn_code">85395000</field>
|
||||
</record>
|
||||
<record id="point_of_sale.letter_tray" model="product.product">
|
||||
<field name="l10n_in_hsn_code">4819.60.00</field>
|
||||
<field name="l10n_in_hsn_description">Box files, letter trays, storage boxes and similar articles, of a kind used in offices, shops or the like</field>
|
||||
<field name="l10n_in_hsn_code">48196000</field>
|
||||
</record>
|
||||
<record id="point_of_sale.magnetic_board" model="product.product">
|
||||
<field name="l10n_in_hsn_code">3921.90.99</field>
|
||||
<field name="l10n_in_hsn_description">Other plates, sheets film , foil and strip, of plastics</field>
|
||||
<field name="l10n_in_hsn_code">39219099</field>
|
||||
</record>
|
||||
<record id="point_of_sale.product_product_consumable" model="product.product">
|
||||
<field name="l10n_in_hsn_code">8443.32.90</field>
|
||||
<field name="l10n_in_hsn_description">Other, capable of connecting to an automatic data processing machine or to a network</field>
|
||||
</record>
|
||||
<record id="point_of_sale.monitor_stand" model="product.product">
|
||||
<record id="product.monitor_stand" model="product.product">
|
||||
<field name="l10n_in_hsn_code">9403</field>
|
||||
<field name="l10n_in_hsn_description">Other furniture and parts thereof.</field>
|
||||
</record>
|
||||
<record id="point_of_sale.newspaper_rack" model="product.product">
|
||||
<field name="l10n_in_hsn_code">9403.10.90</field>
|
||||
<field name="l10n_in_hsn_description">Metal furniture of a kind used in offices</field>
|
||||
<field name="l10n_in_hsn_code">94031090</field>
|
||||
</record>
|
||||
<record id="point_of_sale.small_shelf" model="product.product">
|
||||
<field name="l10n_in_hsn_code">9403.10.90</field>
|
||||
<field name="l10n_in_hsn_description">Metal furniture of a kind used in offices</field>
|
||||
<field name="l10n_in_hsn_code">94031090</field>
|
||||
</record>
|
||||
<record id="point_of_sale.product_product_tip" model="product.product">
|
||||
<field name="l10n_in_hsn_code">8209.00.90</field>
|
||||
<field name="l10n_in_hsn_description">Plates, sticks, tips and the like for tools, unmounted, of cermets.</field>
|
||||
<field name="l10n_in_hsn_code">82090090</field>
|
||||
</record>
|
||||
<record id="point_of_sale.wall_shelf" model="product.product">
|
||||
<field name="l10n_in_hsn_code">9403.10.90</field>
|
||||
<field name="l10n_in_hsn_description">Metal furniture of a kind used in offices</field>
|
||||
<field name="l10n_in_hsn_code">94031090</field>
|
||||
</record>
|
||||
<record id="point_of_sale.whiteboard" model="product.product">
|
||||
<field name="l10n_in_hsn_code">3926.10.99</field>
|
||||
<field name="l10n_in_hsn_description">Office supplies of a kind classified as stationary other than pins,clips, and writing instruments</field>
|
||||
<field name="l10n_in_hsn_code">39261099</field>
|
||||
</record>
|
||||
<record id="point_of_sale.whiteboard_pen" model="product.product">
|
||||
<field name="l10n_in_hsn_code">9608</field>
|
||||
<field name="l10n_in_hsn_description">Ball point pens; felt tipped and other porous-tipped pens and markers; fountain pens, stylograph pens and other pens; duplicating stylos; propelling or sliding pencils; pen-holders, pencilholders and similar holders; parts (including caps and clips) of the foregoing articles, othe than those of heading 9609
|
||||
</field>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
|
|
|
|||
290
odoo-bringout-oca-ocb-l10n_in_pos/l10n_in_pos/i18n/hi.po
Normal file
290
odoo-bringout-oca-ocb-l10n_in_pos/l10n_in_pos/i18n/hi.po
Normal file
|
|
@ -0,0 +1,290 @@
|
|||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * l10n_in_pos
|
||||
#
|
||||
# Weblate <noreply-mt-weblate@weblate.org>, 2025.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server 19.0\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2026-03-06 19:06+0000\n"
|
||||
"PO-Revision-Date: 2025-11-17 03:12+0000\n"
|
||||
"Last-Translator: Weblate <noreply-mt-weblate@weblate.org>\n"
|
||||
"Language-Team: Hindi <https://translate.odoo.com/projects/odoo-19-l10n/"
|
||||
"l10n_in_pos/hi/>\n"
|
||||
"Language: hi\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n==0 || n==1);\n"
|
||||
"X-Generator: Weblate 5.12.2\n"
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#: model_terms:ir.ui.view,arch_db:l10n_in_pos.res_config_settings_view_form_l10n_in_pos_inherit
|
||||
msgid ""
|
||||
"<span>Please note that the kiosk for INR currency only works with Razorpay "
|
||||
"terminal</span>"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#. odoo-javascript
|
||||
#: code:addons/l10n_in_pos/static/src/app/components/popups/hsn_code_dialog/hsn_code_dialog.xml:0
|
||||
msgid ""
|
||||
"As POS sales are reported in GSTR-1, HSN/SAC codes must be set on all "
|
||||
"taxable products."
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#. odoo-javascript
|
||||
#: code:addons/l10n_in_pos/static/src/app/screens/receipt_screen/pos_receipt.xml:0
|
||||
msgid "CESS"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#. odoo-javascript
|
||||
#: code:addons/l10n_in_pos/static/src/app/screens/receipt_screen/pos_receipt.xml:0
|
||||
msgid "CGST"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#: model:ir.model,name:l10n_in_pos.model_pos_bill
|
||||
msgid "Coins/Bills"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#: model:ir.model,name:l10n_in_pos.model_res_company
|
||||
msgid "Companies"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#. odoo-javascript
|
||||
#: code:addons/l10n_in_pos/static/src/app/components/popups/company_state_dialog/company_state_dialog.xml:0
|
||||
msgid "Company address is missing"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#: model_terms:ir.actions.act_window,help:l10n_in_pos.action_missing_hsn_product
|
||||
msgid "Create a new product variant"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#: model:ir.model.fields,field_description:l10n_in_pos.field_account_move__display_name
|
||||
#: model:ir.model.fields,field_description:l10n_in_pos.field_account_move_line__display_name
|
||||
#: model:ir.model.fields,field_description:l10n_in_pos.field_account_tax__display_name
|
||||
#: model:ir.model.fields,field_description:l10n_in_pos.field_pos_bill__display_name
|
||||
#: model:ir.model.fields,field_description:l10n_in_pos.field_pos_config__display_name
|
||||
#: model:ir.model.fields,field_description:l10n_in_pos.field_pos_order__display_name
|
||||
#: model:ir.model.fields,field_description:l10n_in_pos.field_pos_order_line__display_name
|
||||
#: model:ir.model.fields,field_description:l10n_in_pos.field_pos_session__display_name
|
||||
#: model:ir.model.fields,field_description:l10n_in_pos.field_product_product__display_name
|
||||
#: model:ir.model.fields,field_description:l10n_in_pos.field_product_template__display_name
|
||||
#: model:ir.model.fields,field_description:l10n_in_pos.field_res_company__display_name
|
||||
msgid "Display Name"
|
||||
msgstr "डिस्प्ले का नाम"
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#: model:ir.model,name:l10n_in_pos.model_account_tax
|
||||
msgid "ETA tax codes mixin"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#. odoo-javascript
|
||||
#: code:addons/l10n_in_pos/static/src/app/components/popups/product_info_popup/product_info_popup.js:0
|
||||
msgid "GST:"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#. odoo-javascript
|
||||
#: code:addons/l10n_in_pos/static/src/app/components/popups/hsn_code_dialog/hsn_code_dialog.xml:0
|
||||
msgid "Go to Products"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#. odoo-javascript
|
||||
#: code:addons/l10n_in_pos/static/src/app/components/popups/company_state_dialog/company_state_dialog.xml:0
|
||||
msgid "Go to company configuration"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#. odoo-javascript
|
||||
#: code:addons/l10n_in_pos/static/src/app/screens/receipt_screen/pos_receipt.xml:0
|
||||
msgid "HSN Code"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#. odoo-javascript
|
||||
#: code:addons/l10n_in_pos/static/src/app/screens/receipt_screen/pos_receipt.xml:0
|
||||
msgid "HSN Code:"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#: model:ir.model.fields,field_description:l10n_in_pos.field_product_product__l10n_in_hsn_missing_in_pos
|
||||
msgid "HSN Missing in POS"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#. odoo-javascript
|
||||
#: code:addons/l10n_in_pos/static/src/app/screens/receipt_screen/pos_receipt.xml:0
|
||||
msgid "HSN Summary"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#: model:ir.model.fields,field_description:l10n_in_pos.field_pos_order_line__l10n_in_hsn_code
|
||||
#: model_terms:ir.ui.view,arch_db:l10n_in_pos.product_tree_hsn_code
|
||||
msgid "HSN/SAC Code"
|
||||
msgstr "HSN/SAC कोड"
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#: model:ir.model.fields,field_description:l10n_in_pos.field_account_move__id
|
||||
#: model:ir.model.fields,field_description:l10n_in_pos.field_account_move_line__id
|
||||
#: model:ir.model.fields,field_description:l10n_in_pos.field_account_tax__id
|
||||
#: model:ir.model.fields,field_description:l10n_in_pos.field_pos_bill__id
|
||||
#: model:ir.model.fields,field_description:l10n_in_pos.field_pos_config__id
|
||||
#: model:ir.model.fields,field_description:l10n_in_pos.field_pos_order__id
|
||||
#: model:ir.model.fields,field_description:l10n_in_pos.field_pos_order_line__id
|
||||
#: model:ir.model.fields,field_description:l10n_in_pos.field_pos_session__id
|
||||
#: model:ir.model.fields,field_description:l10n_in_pos.field_product_product__id
|
||||
#: model:ir.model.fields,field_description:l10n_in_pos.field_product_template__id
|
||||
#: model:ir.model.fields,field_description:l10n_in_pos.field_res_company__id
|
||||
msgid "ID"
|
||||
msgstr "आईडी"
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#. odoo-javascript
|
||||
#: code:addons/l10n_in_pos/static/src/app/screens/receipt_screen/pos_receipt.xml:0
|
||||
msgid "IGST"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#. odoo-javascript
|
||||
#: code:addons/l10n_in_pos/static/src/app/screens/receipt_screen/pos_receipt.xml:0
|
||||
msgid "INVOICE"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#. odoo-javascript
|
||||
#: code:addons/l10n_in_pos/static/src/app/components/popups/hsn_code_dialog/hsn_code_dialog.xml:0
|
||||
msgid ""
|
||||
"If you know the HSN codes, you can go to Products and set the missing ones "
|
||||
"there."
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#: model:ir.model,name:l10n_in_pos.model_account_move
|
||||
msgid "Journal Entry"
|
||||
msgstr "जर्नल एंट्री"
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#: model:ir.model,name:l10n_in_pos.model_account_move_line
|
||||
msgid "Journal Item"
|
||||
msgstr "जर्नल आइटम"
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#: model:ir.actions.act_window,name:l10n_in_pos.action_missing_hsn_product
|
||||
msgid "Missing HSN Products"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#. odoo-javascript
|
||||
#: code:addons/l10n_in_pos/static/src/app/components/popups/hsn_code_dialog/hsn_code_dialog.xml:0
|
||||
msgid "Missing HSN/SAC Codes"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#. odoo-javascript
|
||||
#: code:addons/l10n_in_pos/static/src/app/components/popups/company_state_dialog/company_state_dialog.xml:0
|
||||
msgid "Ok"
|
||||
msgstr "ठीक है"
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#. odoo-javascript
|
||||
#: code:addons/l10n_in_pos/static/src/app/screens/receipt_screen/pos_receipt.xml:0
|
||||
msgid "Phone:"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#: model:ir.model,name:l10n_in_pos.model_pos_config
|
||||
msgid "Point of Sale Configuration"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#: model:ir.model,name:l10n_in_pos.model_pos_order_line
|
||||
msgid "Point of Sale Order Lines"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#: model:ir.model,name:l10n_in_pos.model_pos_order
|
||||
msgid "Point of Sale Orders"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#: model:ir.model,name:l10n_in_pos.model_pos_session
|
||||
msgid "Point of Sale Session"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#: model:ir.model,name:l10n_in_pos.model_product_template
|
||||
msgid "Product"
|
||||
msgstr "प्रॉडक्ट"
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#: model:ir.model,name:l10n_in_pos.model_product_product
|
||||
msgid "Product Variant"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#. odoo-javascript
|
||||
#: code:addons/l10n_in_pos/static/src/app/screens/receipt_screen/pos_receipt.xml:0
|
||||
msgid "Rate%"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#. odoo-javascript
|
||||
#: code:addons/l10n_in_pos/static/src/app/screens/receipt_screen/pos_receipt.xml:0
|
||||
msgid "SGST"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#. odoo-javascript
|
||||
#: code:addons/l10n_in_pos/static/src/app/components/popups/company_state_dialog/company_state_dialog.xml:0
|
||||
msgid "Set the address of your company (Don't forget the State field)"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#. odoo-javascript
|
||||
#: code:addons/l10n_in_pos/static/src/app/components/popups/hsn_code_dialog/hsn_code_dialog.xml:0
|
||||
msgid ""
|
||||
"Some products are missing this information, which prevents the session from "
|
||||
"being closed."
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#. odoo-javascript
|
||||
#: code:addons/l10n_in_pos/static/src/app/screens/receipt_screen/pos_receipt.xml:0
|
||||
msgid "Tax Invoice"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#. odoo-javascript
|
||||
#: code:addons/l10n_in_pos/static/src/app/components/popups/product_info_popup/product_info_popup.js:0
|
||||
msgid "Total GST:"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#: model_terms:ir.actions.act_window,help:l10n_in_pos.action_missing_hsn_product
|
||||
msgid ""
|
||||
"You must define an HSN for every product you sell through\n"
|
||||
" the point of sale interface."
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#. odoo-javascript
|
||||
#: code:addons/l10n_in_pos/static/src/app/components/popups/company_state_dialog/company_state_dialog.xml:0
|
||||
msgid "Your company"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#. odoo-javascript
|
||||
#: code:addons/l10n_in_pos/static/src/app/components/popups/company_state_dialog/company_state_dialog.xml:0
|
||||
msgid "needs to have a correct address in order validate the invoice."
|
||||
msgstr ""
|
||||
|
|
@ -4,10 +4,10 @@
|
|||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server 15.0+e\n"
|
||||
"Project-Id-Version: Odoo Server 19.0+e\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2023-06-12 07:24+0000\n"
|
||||
"PO-Revision-Date: 2023-06-12 07:24+0000\n"
|
||||
"POT-Creation-Date: 2026-03-06 19:06+0000\n"
|
||||
"PO-Revision-Date: 2026-03-06 19:06+0000\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
|
|
@ -16,22 +16,185 @@ msgstr ""
|
|||
"Plural-Forms: \n"
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#: code:addons/l10n_in_pos/models/pos_config.py:0
|
||||
#, python-format
|
||||
msgid "Go to Company configuration"
|
||||
#: model_terms:ir.ui.view,arch_db:l10n_in_pos.res_config_settings_view_form_l10n_in_pos_inherit
|
||||
msgid ""
|
||||
"<span>Please note that the kiosk for INR currency only works with Razorpay "
|
||||
"terminal</span>"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#. openerp-web
|
||||
#: code:addons/l10n_in_pos/static/src/xml/pos_receipt.xml:0
|
||||
#, python-format
|
||||
#. odoo-javascript
|
||||
#: code:addons/l10n_in_pos/static/src/app/components/popups/hsn_code_dialog/hsn_code_dialog.xml:0
|
||||
msgid ""
|
||||
"As POS sales are reported in GSTR-1, HSN/SAC codes must be set on all "
|
||||
"taxable products."
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#. odoo-javascript
|
||||
#: code:addons/l10n_in_pos/static/src/app/screens/receipt_screen/pos_receipt.xml:0
|
||||
msgid "CESS"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#. odoo-javascript
|
||||
#: code:addons/l10n_in_pos/static/src/app/screens/receipt_screen/pos_receipt.xml:0
|
||||
msgid "CGST"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#: model:ir.model,name:l10n_in_pos.model_pos_bill
|
||||
msgid "Coins/Bills"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#: model:ir.model,name:l10n_in_pos.model_res_company
|
||||
msgid "Companies"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#. odoo-javascript
|
||||
#: code:addons/l10n_in_pos/static/src/app/components/popups/company_state_dialog/company_state_dialog.xml:0
|
||||
msgid "Company address is missing"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#: model_terms:ir.actions.act_window,help:l10n_in_pos.action_missing_hsn_product
|
||||
msgid "Create a new product variant"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#: model:ir.model.fields,field_description:l10n_in_pos.field_account_move__display_name
|
||||
#: model:ir.model.fields,field_description:l10n_in_pos.field_account_move_line__display_name
|
||||
#: model:ir.model.fields,field_description:l10n_in_pos.field_account_tax__display_name
|
||||
#: model:ir.model.fields,field_description:l10n_in_pos.field_pos_bill__display_name
|
||||
#: model:ir.model.fields,field_description:l10n_in_pos.field_pos_config__display_name
|
||||
#: model:ir.model.fields,field_description:l10n_in_pos.field_pos_order__display_name
|
||||
#: model:ir.model.fields,field_description:l10n_in_pos.field_pos_order_line__display_name
|
||||
#: model:ir.model.fields,field_description:l10n_in_pos.field_pos_session__display_name
|
||||
#: model:ir.model.fields,field_description:l10n_in_pos.field_product_product__display_name
|
||||
#: model:ir.model.fields,field_description:l10n_in_pos.field_product_template__display_name
|
||||
#: model:ir.model.fields,field_description:l10n_in_pos.field_res_company__display_name
|
||||
msgid "Display Name"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#: model:ir.model,name:l10n_in_pos.model_account_tax
|
||||
msgid "ETA tax codes mixin"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#. odoo-javascript
|
||||
#: code:addons/l10n_in_pos/static/src/app/components/popups/product_info_popup/product_info_popup.js:0
|
||||
msgid "GST:"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#. odoo-javascript
|
||||
#: code:addons/l10n_in_pos/static/src/app/components/popups/hsn_code_dialog/hsn_code_dialog.xml:0
|
||||
msgid "Go to Products"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#. odoo-javascript
|
||||
#: code:addons/l10n_in_pos/static/src/app/components/popups/company_state_dialog/company_state_dialog.xml:0
|
||||
msgid "Go to company configuration"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#. odoo-javascript
|
||||
#: code:addons/l10n_in_pos/static/src/app/screens/receipt_screen/pos_receipt.xml:0
|
||||
msgid "HSN Code"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#. odoo-javascript
|
||||
#: code:addons/l10n_in_pos/static/src/app/screens/receipt_screen/pos_receipt.xml:0
|
||||
msgid "HSN Code:"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#. openerp-web
|
||||
#: code:addons/l10n_in_pos/static/src/xml/pos_receipt.xml:0
|
||||
#, python-format
|
||||
#: model:ir.model.fields,field_description:l10n_in_pos.field_product_product__l10n_in_hsn_missing_in_pos
|
||||
msgid "HSN Missing in POS"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#. odoo-javascript
|
||||
#: code:addons/l10n_in_pos/static/src/app/screens/receipt_screen/pos_receipt.xml:0
|
||||
msgid "HSN Summary"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#: model:ir.model.fields,field_description:l10n_in_pos.field_pos_order_line__l10n_in_hsn_code
|
||||
#: model_terms:ir.ui.view,arch_db:l10n_in_pos.product_tree_hsn_code
|
||||
msgid "HSN/SAC Code"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#: model:ir.model.fields,field_description:l10n_in_pos.field_account_move__id
|
||||
#: model:ir.model.fields,field_description:l10n_in_pos.field_account_move_line__id
|
||||
#: model:ir.model.fields,field_description:l10n_in_pos.field_account_tax__id
|
||||
#: model:ir.model.fields,field_description:l10n_in_pos.field_pos_bill__id
|
||||
#: model:ir.model.fields,field_description:l10n_in_pos.field_pos_config__id
|
||||
#: model:ir.model.fields,field_description:l10n_in_pos.field_pos_order__id
|
||||
#: model:ir.model.fields,field_description:l10n_in_pos.field_pos_order_line__id
|
||||
#: model:ir.model.fields,field_description:l10n_in_pos.field_pos_session__id
|
||||
#: model:ir.model.fields,field_description:l10n_in_pos.field_product_product__id
|
||||
#: model:ir.model.fields,field_description:l10n_in_pos.field_product_template__id
|
||||
#: model:ir.model.fields,field_description:l10n_in_pos.field_res_company__id
|
||||
msgid "ID"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#. odoo-javascript
|
||||
#: code:addons/l10n_in_pos/static/src/app/screens/receipt_screen/pos_receipt.xml:0
|
||||
msgid "IGST"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#. odoo-javascript
|
||||
#: code:addons/l10n_in_pos/static/src/app/screens/receipt_screen/pos_receipt.xml:0
|
||||
msgid "INVOICE"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#. odoo-javascript
|
||||
#: code:addons/l10n_in_pos/static/src/app/components/popups/hsn_code_dialog/hsn_code_dialog.xml:0
|
||||
msgid ""
|
||||
"If you know the HSN codes, you can go to Products and set the missing ones "
|
||||
"there."
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#: model:ir.model,name:l10n_in_pos.model_account_move
|
||||
msgid "Journal Entry"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#: model:ir.model,name:l10n_in_pos.model_account_move_line
|
||||
msgid "Journal Item"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#: model:ir.actions.act_window,name:l10n_in_pos.action_missing_hsn_product
|
||||
msgid "Missing HSN Products"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#. odoo-javascript
|
||||
#: code:addons/l10n_in_pos/static/src/app/components/popups/hsn_code_dialog/hsn_code_dialog.xml:0
|
||||
msgid "Missing HSN/SAC Codes"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#. odoo-javascript
|
||||
#: code:addons/l10n_in_pos/static/src/app/components/popups/company_state_dialog/company_state_dialog.xml:0
|
||||
msgid "Ok"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#. odoo-javascript
|
||||
#: code:addons/l10n_in_pos/static/src/app/screens/receipt_screen/pos_receipt.xml:0
|
||||
msgid "Phone:"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -40,15 +203,84 @@ msgstr ""
|
|||
msgid "Point of Sale Configuration"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#: model:ir.model,name:l10n_in_pos.model_pos_order_line
|
||||
msgid "Point of Sale Order Lines"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#: model:ir.model,name:l10n_in_pos.model_pos_order
|
||||
msgid "Point of Sale Orders"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#: code:addons/l10n_in_pos/models/pos_config.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Your company %s needs to have a correct address in order to open the session.\n"
|
||||
"Set the address of your company (Don't forget the State field)"
|
||||
#: model:ir.model,name:l10n_in_pos.model_pos_session
|
||||
msgid "Point of Sale Session"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#: model:ir.model,name:l10n_in_pos.model_product_template
|
||||
msgid "Product"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#: model:ir.model,name:l10n_in_pos.model_product_product
|
||||
msgid "Product Variant"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#. odoo-javascript
|
||||
#: code:addons/l10n_in_pos/static/src/app/screens/receipt_screen/pos_receipt.xml:0
|
||||
msgid "Rate%"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#. odoo-javascript
|
||||
#: code:addons/l10n_in_pos/static/src/app/screens/receipt_screen/pos_receipt.xml:0
|
||||
msgid "SGST"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#. odoo-javascript
|
||||
#: code:addons/l10n_in_pos/static/src/app/components/popups/company_state_dialog/company_state_dialog.xml:0
|
||||
msgid "Set the address of your company (Don't forget the State field)"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#. odoo-javascript
|
||||
#: code:addons/l10n_in_pos/static/src/app/components/popups/hsn_code_dialog/hsn_code_dialog.xml:0
|
||||
msgid ""
|
||||
"Some products are missing this information, which prevents the session from "
|
||||
"being closed."
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#. odoo-javascript
|
||||
#: code:addons/l10n_in_pos/static/src/app/screens/receipt_screen/pos_receipt.xml:0
|
||||
msgid "Tax Invoice"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#. odoo-javascript
|
||||
#: code:addons/l10n_in_pos/static/src/app/components/popups/product_info_popup/product_info_popup.js:0
|
||||
msgid "Total GST:"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#: model_terms:ir.actions.act_window,help:l10n_in_pos.action_missing_hsn_product
|
||||
msgid ""
|
||||
"You must define an HSN for every product you sell through\n"
|
||||
" the point of sale interface."
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#. odoo-javascript
|
||||
#: code:addons/l10n_in_pos/static/src/app/components/popups/company_state_dialog/company_state_dialog.xml:0
|
||||
msgid "Your company"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_in_pos
|
||||
#. odoo-javascript
|
||||
#: code:addons/l10n_in_pos/static/src/app/components/popups/company_state_dialog/company_state_dialog.xml:0
|
||||
msgid "needs to have a correct address in order validate the invoice."
|
||||
msgstr ""
|
||||
|
|
|
|||
|
|
@ -1,6 +1,14 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from . import pos_order
|
||||
from . import pos_order_line
|
||||
from . import product
|
||||
from . import product_template
|
||||
from . import account_move
|
||||
from . import account_move_line
|
||||
from . import account_tax
|
||||
from . import pos_bill
|
||||
from . import pos_session
|
||||
from . import pos_order
|
||||
from . import pos_config
|
||||
from . import res_company
|
||||
|
|
|
|||
|
|
@ -0,0 +1,14 @@
|
|||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
from odoo import api, models
|
||||
|
||||
|
||||
class AccountMove(models.Model):
|
||||
_inherit = 'account.move'
|
||||
|
||||
@api.depends('pos_session_ids', 'reversed_pos_order_id')
|
||||
def _compute_l10n_in_state_id(self):
|
||||
res = super()._compute_l10n_in_state_id()
|
||||
to_compute = self.filtered(lambda m: m.country_code == 'IN' and not m.l10n_in_state_id and m.journal_id.type == 'general' and (m.pos_session_ids or m.reversed_pos_order_id))
|
||||
for move in to_compute:
|
||||
move.l10n_in_state_id = move.company_id.state_id
|
||||
return res
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
from odoo import models
|
||||
|
||||
|
||||
class AccountMoveLine(models.Model):
|
||||
_inherit = "account.move.line"
|
||||
|
||||
def _get_l10n_in_gstr_section(self, tax_tags_dict):
|
||||
result = super()._get_l10n_in_gstr_section(tax_tags_dict)
|
||||
|
||||
eco_9_5_tag = tax_tags_dict['eco_9_5']
|
||||
all_gst_tags = tax_tags_dict['cgst'] + tax_tags_dict['sgst'] + tax_tags_dict['igst'] + tax_tags_dict['cess']
|
||||
|
||||
def get_section(line):
|
||||
tax_tags = line.tax_tag_ids.ids
|
||||
if any(tag == eco_9_5_tag for tag in tax_tags):
|
||||
return 'sale_eco_9_5'
|
||||
if any(tag in tax_tags for tag in all_gst_tags):
|
||||
return 'sale_b2cs'
|
||||
if any(tax.l10n_in_tax_type == 'nil_rated' for tax in line.tax_ids):
|
||||
return 'sale_nil_rated'
|
||||
if any(tax.l10n_in_tax_type == 'exempt' for tax in line.tax_ids):
|
||||
return 'sale_exempt'
|
||||
if any(tax.l10n_in_tax_type == 'non_gst' for tax in line.tax_ids):
|
||||
return 'sale_non_gst_supplies'
|
||||
return 'sale_out_of_scope'
|
||||
|
||||
in_pos_closing_and_reversed_lines = self.filtered(
|
||||
lambda l: l.move_id.country_code == 'IN'
|
||||
and l.move_id.move_type == 'entry'
|
||||
and l.display_type in ('product', 'tax')
|
||||
and (l.move_id.sudo().pos_session_ids or l.move_id.sudo().reversed_pos_order_id)
|
||||
)
|
||||
if not in_pos_closing_and_reversed_lines:
|
||||
return result
|
||||
|
||||
move_lines_by_gstr_section = in_pos_closing_and_reversed_lines.grouped(get_section)
|
||||
|
||||
for section, lines in move_lines_by_gstr_section.items():
|
||||
result[section] = result.get(section, self.env['account.move.line']) | lines
|
||||
|
||||
return result
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
from odoo import api, models
|
||||
|
||||
|
||||
class AccountTax(models.Model):
|
||||
_inherit = 'account.tax'
|
||||
|
||||
@api.model
|
||||
def _load_pos_data_fields(self, config):
|
||||
fields = super()._load_pos_data_fields(config)
|
||||
fields += ['l10n_in_gst_tax_type']
|
||||
return fields
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
from odoo import api, models
|
||||
from odoo.fields import Domain
|
||||
|
||||
|
||||
class PosBill(models.Model):
|
||||
_inherit = "pos.bill"
|
||||
|
||||
@api.model
|
||||
def _load_pos_data_domain(self, data, config):
|
||||
domain = super()._load_pos_data_domain(data, config)
|
||||
|
||||
if self.env.company.country_code == 'IN':
|
||||
domain = Domain.AND([domain, [('value', '>=', 1.0), ('value', '<=', 2000.0)]])
|
||||
|
||||
return domain
|
||||
|
|
@ -1,24 +1,8 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
from odoo import models
|
||||
from odoo.exceptions import RedirectWarning
|
||||
from odoo.tools.translate import _
|
||||
|
||||
|
||||
class PosConfig(models.Model):
|
||||
_inherit = 'pos.config'
|
||||
|
||||
def open_ui(self):
|
||||
for config in self:
|
||||
if config.company_id.country_id.code == 'IN' and not config.company_id.state_id:
|
||||
msg = _("Your company %s needs to have a correct address in order to open the session.\n"
|
||||
"Set the address of your company (Don't forget the State field)") % (config.company_id.name)
|
||||
action = {
|
||||
"view_mode": "form",
|
||||
"res_model": "res.company",
|
||||
"type": "ir.actions.act_window",
|
||||
"res_id" : config.company_id.id,
|
||||
"views": [[self.env.ref("base.view_company_form").id, "form"]],
|
||||
}
|
||||
raise RedirectWarning(msg, action, _('Go to Company configuration'))
|
||||
return super(PosConfig, self).open_ui()
|
||||
def _is_quantities_set(self):
|
||||
return self.company_id.l10n_in_is_gst_registered or super()._is_quantities_set()
|
||||
|
|
|
|||
|
|
@ -1,20 +1,13 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import api, fields, models
|
||||
from odoo import models
|
||||
|
||||
|
||||
class PosOrder(models.Model):
|
||||
_inherit = 'pos.order'
|
||||
|
||||
def _prepare_invoice_vals(self):
|
||||
vals = super()._prepare_invoice_vals()
|
||||
if self.session_id.company_id.country_id.code == 'IN':
|
||||
partner = self.partner_id
|
||||
l10n_in_gst_treatment = partner.l10n_in_gst_treatment
|
||||
if not l10n_in_gst_treatment and partner.country_id and partner.country_id.code != 'IN':
|
||||
l10n_in_gst_treatment = 'overseas'
|
||||
if not l10n_in_gst_treatment:
|
||||
l10n_in_gst_treatment = partner.vat and 'regular' or 'consumer'
|
||||
vals['l10n_in_gst_treatment'] = l10n_in_gst_treatment
|
||||
return vals
|
||||
def _prepare_product_aml_dict(self, base_line_vals, update_base_line_vals, rate, sign):
|
||||
res = super()._prepare_product_aml_dict(base_line_vals, update_base_line_vals, rate, sign)
|
||||
if self.company_id.account_fiscal_country_id.code == 'IN':
|
||||
res.update({
|
||||
'l10n_in_hsn_code': base_line_vals['l10n_in_hsn_code'],
|
||||
})
|
||||
return res
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import api, fields, models
|
||||
|
||||
|
||||
class PosOrderLine(models.Model):
|
||||
_inherit = "pos.order.line"
|
||||
|
||||
l10n_in_hsn_code = fields.Char(string="HSN/SAC Code", compute="_compute_l10n_in_hsn_code", store=True, readonly=False, copy=False)
|
||||
|
||||
@api.depends('product_id')
|
||||
def _compute_l10n_in_hsn_code(self):
|
||||
indian_lines = self.filtered(lambda line: line.company_id.account_fiscal_country_id.code == 'IN')
|
||||
(self - indian_lines).l10n_in_hsn_code = False
|
||||
for line in indian_lines:
|
||||
if line.product_id:
|
||||
line.l10n_in_hsn_code = line.product_id.l10n_in_hsn_code
|
||||
|
||||
@api.model
|
||||
def _load_pos_data_fields(self, config):
|
||||
params = super()._load_pos_data_fields(config)
|
||||
if self.env.company.country_id.code == 'IN':
|
||||
params += ['l10n_in_hsn_code']
|
||||
return params
|
||||
|
||||
def _prepare_base_line_for_taxes_computation(self):
|
||||
res = super()._prepare_base_line_for_taxes_computation()
|
||||
if self.company_id.l10n_in_is_gst_registered:
|
||||
res.update({
|
||||
'l10n_in_hsn_code': self.l10n_in_hsn_code,
|
||||
})
|
||||
return res
|
||||
|
|
@ -1,13 +1,46 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import models
|
||||
|
||||
|
||||
class PosSession(models.Model):
|
||||
_inherit = 'pos.session'
|
||||
|
||||
def _loader_params_product_product(self):
|
||||
result = super()._loader_params_product_product()
|
||||
result['search_params']['fields'].append('l10n_in_hsn_code')
|
||||
return result
|
||||
def _get_sale_key(self, base_line):
|
||||
res = super()._get_sale_key(base_line)
|
||||
if self.config_id.company_id.l10n_in_is_gst_registered:
|
||||
res.update({
|
||||
'uom_id': base_line['uom_id'].id,
|
||||
'l10n_in_hsn_code': base_line['l10n_in_hsn_code'],
|
||||
})
|
||||
return res
|
||||
|
||||
def _get_sale_vals(self, key, sale_vals):
|
||||
res = super()._get_sale_vals(key, sale_vals)
|
||||
if self.config_id.company_id.l10n_in_is_gst_registered:
|
||||
res.update({
|
||||
'l10n_in_hsn_code': key['l10n_in_hsn_code'],
|
||||
'product_uom_id': key['uom_id'],
|
||||
})
|
||||
return res
|
||||
|
||||
def set_missing_hsn_codes_in_pos_orders(self):
|
||||
self.ensure_one()
|
||||
PosOrderLine = self.env['pos.order.line']
|
||||
base_domain = [
|
||||
('order_id.session_id', '=', self.id),
|
||||
('order_id.account_move', '=', False),
|
||||
('l10n_in_hsn_code', '=', False),
|
||||
('tax_ids', '!=', False),
|
||||
]
|
||||
|
||||
# Lines where product already has HSN
|
||||
lines_with_product_hsn = PosOrderLine.search(
|
||||
base_domain + [('product_id.l10n_in_hsn_code', '!=', False)]
|
||||
)
|
||||
for line in lines_with_product_hsn:
|
||||
line.l10n_in_hsn_code = line.product_id.l10n_in_hsn_code
|
||||
|
||||
# Lines where product itself is missing HSN
|
||||
missing_hsn_lines = PosOrderLine.search(
|
||||
base_domain + [('product_id.l10n_in_hsn_code', '=', False)]
|
||||
)
|
||||
return missing_hsn_lines
|
||||
|
|
|
|||
|
|
@ -0,0 +1,70 @@
|
|||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import api, fields, models
|
||||
|
||||
|
||||
class ProductProduct(models.Model):
|
||||
_inherit = "product.product"
|
||||
|
||||
l10n_in_hsn_missing_in_pos = fields.Boolean(
|
||||
search="_search_l10n_in_hsn_missing_in_pos",
|
||||
store=False,
|
||||
string="HSN Missing in POS",
|
||||
)
|
||||
|
||||
def _search_l10n_in_hsn_missing_in_pos(self, operator, value):
|
||||
if operator not in ("=", "!="):
|
||||
return NotImplemented
|
||||
|
||||
domain = [
|
||||
("order_id.session_id.state", "!=", "closed"),
|
||||
("order_id.account_move", "=", False),
|
||||
("product_id.product_tmpl_id.l10n_in_hsn_code", "=", False),
|
||||
("product_id.product_tmpl_id.taxes_id", "!=", False),
|
||||
]
|
||||
grouped_data = self.env["pos.order.line"]._read_group(
|
||||
domain,
|
||||
aggregates=["__count"],
|
||||
groupby=["product_id"],
|
||||
)
|
||||
|
||||
product_ids = [row[0].id for row in grouped_data]
|
||||
positive = (operator == "=" and value) or (operator == "!=" and not value)
|
||||
|
||||
return [("id", "in" if positive else "not in", product_ids)]
|
||||
|
||||
@api.model
|
||||
def l10n_in_get_hsn_code_action(self):
|
||||
"""
|
||||
Returns the action to open the HSN code dialog with the given products.
|
||||
FIXME: This method dynamically creates a view at runtime.
|
||||
FIXME: Remove this method and the dynamic view in master.
|
||||
"""
|
||||
|
||||
action_xml_id = 'l10n_in_pos.action_missing_hsn_product'
|
||||
action = self.env.ref(action_xml_id, False)
|
||||
if not action:
|
||||
action = self.env['ir.actions.act_window'].sudo().create({
|
||||
'name': 'Missing HSN Products',
|
||||
'type': 'ir.actions.act_window',
|
||||
'res_model': 'product.product',
|
||||
'view_mode': 'kanban,list,form',
|
||||
'domain': [
|
||||
('l10n_in_hsn_missing_in_pos', '=', True)
|
||||
],
|
||||
'help': """
|
||||
<p class="o_view_nocontent_smiling_face">
|
||||
Create a new product variant
|
||||
</p>
|
||||
<p>
|
||||
You must define an HSN for every product you sell through
|
||||
the point of sale interface.
|
||||
</p>
|
||||
""",
|
||||
})
|
||||
self.env['ir.model.data']._update_xmlids([{
|
||||
'xml_id': action_xml_id,
|
||||
'record': action,
|
||||
}])
|
||||
|
||||
return action_xml_id
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import api, models
|
||||
|
||||
|
||||
class ProductTemplate(models.Model):
|
||||
_inherit = "product.template"
|
||||
|
||||
@api.model
|
||||
def _load_pos_data_fields(self, config):
|
||||
fields = super()._load_pos_data_fields(config)
|
||||
if self.env.company.country_id.code == 'IN':
|
||||
fields += ['l10n_in_hsn_code']
|
||||
return fields
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import api, models
|
||||
|
||||
|
||||
class ResCompany(models.Model):
|
||||
_inherit = "res.company"
|
||||
|
||||
@api.model
|
||||
def _load_pos_data_fields(self, config):
|
||||
fields = super()._load_pos_data_fields(config)
|
||||
if self.env.company.country_id.code == 'IN':
|
||||
fields += ['l10n_in_is_gst_registered']
|
||||
return fields
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
import { CashMovePopup } from "@point_of_sale/app/components/popups/cash_move_popup/cash_move_popup";
|
||||
|
||||
import { patch } from "@web/core/utils/patch";
|
||||
import { companyStateDialog } from "@l10n_in_pos/app/components/popups/company_state_dialog/company_state_dialog";
|
||||
|
||||
patch(CashMovePopup.prototype, {
|
||||
async confirm() {
|
||||
await this.pos.data.read("res.company", [this.pos.company.id]);
|
||||
if (this.pos.company.country_id?.code === "IN" && !this.pos.company.state_id) {
|
||||
this.dialog.add(companyStateDialog);
|
||||
return;
|
||||
}
|
||||
return await super.confirm();
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
import { ClosePosPopup } from "@point_of_sale/app/components/popups/closing_popup/closing_popup";
|
||||
|
||||
import { patch } from "@web/core/utils/patch";
|
||||
import { useService } from "@web/core/utils/hooks";
|
||||
import { companyStateDialog } from "@l10n_in_pos/app/components/popups/company_state_dialog/company_state_dialog";
|
||||
import { hsnCodeDialog } from "@l10n_in_pos/app/components/popups/hsn_code_dialog/hsn_code_dialog";
|
||||
|
||||
patch(ClosePosPopup.prototype, {
|
||||
setup() {
|
||||
super.setup();
|
||||
this.orm = useService("orm");
|
||||
},
|
||||
|
||||
async confirm() {
|
||||
await this.pos.data.read("res.company", [this.pos.company.id]);
|
||||
if (this.pos.company.country_id?.code === "IN" && !this.pos.company.state_id) {
|
||||
this.dialog.add(companyStateDialog);
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.pos.company.l10n_in_is_gst_registered) {
|
||||
const missingHsnLines = await this.orm.call(
|
||||
"pos.session",
|
||||
"set_missing_hsn_codes_in_pos_orders",
|
||||
[this.pos.session.id]
|
||||
);
|
||||
if (missingHsnLines?.length) {
|
||||
this.dialog.add(hsnCodeDialog);
|
||||
return;
|
||||
}
|
||||
}
|
||||
return await super.confirm();
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
import { Dialog } from "@web/core/dialog/dialog";
|
||||
import { Component } from "@odoo/owl";
|
||||
import { usePos } from "@point_of_sale/app/hooks/pos_hook";
|
||||
|
||||
export class companyStateDialog extends Component {
|
||||
static components = { Dialog };
|
||||
static template = "l10n_in_pos.companyStateDialog";
|
||||
static props = {
|
||||
close: Function,
|
||||
};
|
||||
|
||||
setup() {
|
||||
this.pos = usePos();
|
||||
}
|
||||
|
||||
redirect() {
|
||||
window.location = "/odoo/companies/" + this.pos.company.id;
|
||||
}
|
||||
|
||||
onClose() {
|
||||
this.props.close();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<templates id="template" xml:space="preserve">
|
||||
|
||||
<t t-name="l10n_in_pos.companyStateDialog">
|
||||
<Dialog size="'md'" title.translate="Company address is missing">
|
||||
<div>
|
||||
<p>Your company <span><t t-esc="this.pos.company.name"/></span> needs to have a correct address in order validate the invoice.</p>
|
||||
<p>Set the address of your company (Don't forget the State field)</p>
|
||||
</div>
|
||||
<t t-set-slot="footer">
|
||||
<div class="modal-footer-right d-flex gap-2">
|
||||
<button class="button icon btn btn-lg btn-primary" t-on-click="redirect">
|
||||
Go to company configuration
|
||||
</button>
|
||||
<button class="button btn btn-secondary" t-on-click="onClose">
|
||||
Ok
|
||||
</button>
|
||||
</div>
|
||||
</t>
|
||||
</Dialog>
|
||||
</t>
|
||||
|
||||
</templates>
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
import { Component } from "@odoo/owl";
|
||||
import { Dialog } from "@web/core/dialog/dialog";
|
||||
import { usePos } from "@point_of_sale/app/hooks/pos_hook";
|
||||
|
||||
export class hsnCodeDialog extends Component {
|
||||
static components = { Dialog };
|
||||
static template = "l10n_in_pos.hsnCodeDialog";
|
||||
static props = {
|
||||
close: Function,
|
||||
};
|
||||
|
||||
setup() {
|
||||
this.pos = usePos();
|
||||
}
|
||||
|
||||
async redirect() {
|
||||
// Close dialog first
|
||||
this.props.close();
|
||||
const action_xml_id = await this.pos.data.call(
|
||||
"product.product",
|
||||
"l10n_in_get_hsn_code_action",
|
||||
[]
|
||||
);
|
||||
const url = `/odoo/action-${action_xml_id}`;
|
||||
window.open(url, "_blank");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<templates id="template" xml:space="preserve">
|
||||
|
||||
<t t-name="l10n_in_pos.hsnCodeDialog">
|
||||
<Dialog size="'md'" title.translate="Missing HSN/SAC Codes">
|
||||
<div>
|
||||
<p>
|
||||
As POS sales are reported in GSTR-1, HSN/SAC codes must be set on all taxable products.<br/>
|
||||
Some products are missing this information, which prevents the session from being closed.
|
||||
</p>
|
||||
<p>
|
||||
If you know the HSN codes, you can go to Products and set the missing ones there.
|
||||
</p>
|
||||
</div>
|
||||
<t t-set-slot="footer">
|
||||
<div class="modal-footer-right d-flex gap-2">
|
||||
<button class="button icon btn btn-lg btn-primary" t-on-click="redirect">
|
||||
Go to Products
|
||||
</button>
|
||||
</div>
|
||||
</t>
|
||||
</Dialog>
|
||||
</t>
|
||||
|
||||
</templates>
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
import { _t } from "@web/core/l10n/translation";
|
||||
import { ProductInfoPopup } from "@point_of_sale/app/components/popups/product_info_popup/product_info_popup";
|
||||
|
||||
import { patch } from "@web/core/utils/patch";
|
||||
|
||||
patch(ProductInfoPopup.prototype, {
|
||||
get vatLabel() {
|
||||
return this.pos.company.country_id.code === "IN" ? _t("GST:") : super.vatLabel;
|
||||
},
|
||||
get totalVatLabel() {
|
||||
return this.pos.company.country_id.code === "IN" ? _t("Total GST:") : super.totalVatLabel;
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
import { patch } from "@web/core/utils/patch";
|
||||
import { CustomerDisplayPosAdapter } from "@point_of_sale/app/customer_display/customer_display_adapter";
|
||||
|
||||
patch(CustomerDisplayPosAdapter.prototype, {
|
||||
formatOrderData(order) {
|
||||
super.formatOrderData(order);
|
||||
this.data.onlinePaymentData = { ...(order.onlinePaymentData || {}) };
|
||||
},
|
||||
getOrderlineData(line) {
|
||||
const data = super.getOrderlineData(line);
|
||||
data.l10n_in_hsn_code = line.getProduct().l10n_in_hsn_code || "";
|
||||
return data;
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
import { InvoiceButton } from "@point_of_sale/app/screens/ticket_screen/invoice_button/invoice_button";
|
||||
|
||||
import { patch } from "@web/core/utils/patch";
|
||||
import { companyStateDialog } from "@l10n_in_pos/app/components/popups/company_state_dialog/company_state_dialog";
|
||||
|
||||
patch(InvoiceButton.prototype, {
|
||||
async click() {
|
||||
await this.pos.data.read("res.company", [this.pos.company.id]);
|
||||
if (this.pos.company.country_id?.code === "IN" && !this.pos.company.state_id) {
|
||||
this.dialog.add(companyStateDialog);
|
||||
return;
|
||||
}
|
||||
return await super.click();
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
import { PaymentScreen } from "@point_of_sale/app/screens/payment_screen/payment_screen";
|
||||
|
||||
import { patch } from "@web/core/utils/patch";
|
||||
import { companyStateDialog } from "@l10n_in_pos/app/components/popups/company_state_dialog/company_state_dialog";
|
||||
|
||||
patch(PaymentScreen.prototype, {
|
||||
async toggleIsToInvoice() {
|
||||
await this.pos.data.read("res.company", [this.pos.company.id]);
|
||||
if (this.pos.company.country_id?.code === "IN" && !this.pos.company.state_id) {
|
||||
this.dialog.add(companyStateDialog);
|
||||
return;
|
||||
}
|
||||
return await super.toggleIsToInvoice();
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
import { PosOrder } from "@point_of_sale/app/models/pos_order";
|
||||
import { patch } from "@web/core/utils/patch";
|
||||
import { accountTaxHelpers } from "@account/helpers/account_tax";
|
||||
import { formatCurrency } from "@point_of_sale/app/models/utils/currency";
|
||||
|
||||
patch(PosOrder.prototype, {
|
||||
get isInCompany() {
|
||||
return this.company.country_id?.code === "IN";
|
||||
},
|
||||
_prepareL10nInHsnSummary() {
|
||||
const company = this.company;
|
||||
const orderLines = this.lines;
|
||||
|
||||
// If each line is negative, we assume it's a refund order.
|
||||
// It's a normal order if it doesn't contain a line (useful for pos_settle_due).
|
||||
// TODO: Properly differentiate refund orders from normal ones.
|
||||
const documentSign = this.isRefund ? -1 : 1;
|
||||
const baseLines = orderLines.map((line) =>
|
||||
accountTaxHelpers.prepare_base_line_for_taxes_computation(
|
||||
line,
|
||||
line.prepareBaseLineForTaxesComputationExtraValues({
|
||||
quantity: documentSign * line.qty,
|
||||
})
|
||||
)
|
||||
);
|
||||
accountTaxHelpers.add_tax_details_in_base_lines(baseLines, company);
|
||||
accountTaxHelpers.round_base_lines_tax_details(baseLines, company);
|
||||
const hsnSummary = accountTaxHelpers.l10n_in_get_hsn_summary_table(baseLines, false);
|
||||
if (hsnSummary) {
|
||||
for (const item of hsnSummary.items) {
|
||||
for (const key of [
|
||||
"tax_amount_igst",
|
||||
"tax_amount_cgst",
|
||||
"tax_amount_sgst",
|
||||
"tax_amount_cess",
|
||||
]) {
|
||||
item[key] = formatCurrency(item[key], this.currency);
|
||||
}
|
||||
}
|
||||
}
|
||||
return hsnSummary;
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
import { PosOrderline } from "@point_of_sale/app/models/pos_order_line";
|
||||
import { patch } from "@web/core/utils/patch";
|
||||
|
||||
patch(PosOrderline.prototype, {
|
||||
setup(vals) {
|
||||
return super.setup(...arguments);
|
||||
},
|
||||
|
||||
// EXTENDS 'point_of_sale'
|
||||
prepareBaseLineForTaxesComputationExtraValues(customValues = {}) {
|
||||
const extraValues = super.prepareBaseLineForTaxesComputationExtraValues(customValues);
|
||||
extraValues.l10n_in_hsn_code = this.product_id?.l10n_in_hsn_code;
|
||||
return extraValues;
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<templates id="template" xml:space="preserve">
|
||||
<t t-name="l10n_in_pos.ReceiptHeader" t-inherit="point_of_sale.ReceiptHeader" t-inherit-mode="extension">
|
||||
<xpath expr="//div[hasclass('pos-receipt-customer')]" position="inside">
|
||||
<t t-if="order.partner_id and order.company?.country_id?.code == 'IN'">
|
||||
<t t-if="order.partner_id.phone">
|
||||
<div>
|
||||
<span>Phone: </span>
|
||||
<t t-out="order.partner_id.phone" />
|
||||
</div>
|
||||
</t>
|
||||
<br />
|
||||
</t>
|
||||
</xpath>
|
||||
<xpath expr="//span[hasclass('pos-receipt-vat')]" position="after">
|
||||
<span t-if="order.isInCompany and !order.isToInvoice()" class="pos-receipt-vat">
|
||||
INVOICE <t t-esc="order.invoiceName" />
|
||||
</span>
|
||||
</xpath>
|
||||
<xpath expr="//span[@class='ticket-name-prefix']" position="attributes">
|
||||
<attribute name="t-if">!order.isInCompany</attribute>
|
||||
</xpath>
|
||||
<xpath expr="//span[@class='ticket-name-prefix']" position="after">
|
||||
<span t-if="order.isInCompany" class="ticket-name-prefix">
|
||||
Tax Invoice
|
||||
</span>
|
||||
</xpath>
|
||||
</t>
|
||||
|
||||
<t t-name="l10n_in_pos.OrderReceipt" t-inherit="point_of_sale.OrderReceipt" t-inherit-mode="extension">
|
||||
<xpath expr="//Orderline" position="inside">
|
||||
<t t-if="line.l10n_in_hsn_code and header.company.country_id?.code === 'IN'">
|
||||
<div class="pos-receipt-left-padding">
|
||||
<span>HSN Code: </span>
|
||||
<t t-out="line.l10n_in_hsn_code"/>
|
||||
</div>
|
||||
</t>
|
||||
</xpath>
|
||||
<xpath expr="//div[@class='before-footer']" position="after">
|
||||
<t t-set="l10n_in_hsn_summary" t-value="order._prepareL10nInHsnSummary()"/>
|
||||
<table t-if="l10n_in_hsn_summary and header.company.country_id?.code === 'IN' and l10n_in_hsn_summary.items.length > 0"
|
||||
class="l10n_in_hsn_summary_table pt-3 w-100">
|
||||
<tr>
|
||||
<th class="text-center fw-bolder" colspan="6">HSN Summary</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class="text-center">HSN Code</th>
|
||||
<th class="text-center">Rate%</th>
|
||||
<th class="text-center" t-if="l10n_in_hsn_summary.has_gst">CGST</th>
|
||||
<th class="text-center" t-if="l10n_in_hsn_summary.has_gst">SGST</th>
|
||||
<th class="text-center" t-if="l10n_in_hsn_summary.has_igst">IGST</th>
|
||||
<th class="text-center" t-if="l10n_in_hsn_summary.has_cess">CESS</th>
|
||||
</tr>
|
||||
<tr t-foreach="l10n_in_hsn_summary.items" t-as="item" t-key="item_index">
|
||||
<td class="text-center" t-out="item.l10n_in_hsn_code"/>
|
||||
<td class="text-center"><t t-out="item.rate"/> %</td>
|
||||
<td class="text-center" t-if="l10n_in_hsn_summary.has_gst" t-out="item.tax_amount_cgst"/>
|
||||
<td class="text-center" t-if="l10n_in_hsn_summary.has_gst" t-out="item.tax_amount_sgst"/>
|
||||
<td class="text-center" t-if="l10n_in_hsn_summary.has_igst" t-out="item.tax_amount_igst"/>
|
||||
<td class="text-center" t-if="l10n_in_hsn_summary.has_cess" t-out="item.tax_amount_cess"/>
|
||||
</tr>
|
||||
</table>
|
||||
</xpath>
|
||||
</t>
|
||||
</templates>
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
odoo.define('l10n_in_pos.receipt', function (require) {
|
||||
"use strict";
|
||||
|
||||
var { Orderline } = require('point_of_sale.models');
|
||||
const Registries = require('point_of_sale.Registries');
|
||||
|
||||
|
||||
const L10nInOrderline = (Orderline) => class L10nInOrderline extends Orderline {
|
||||
export_for_printing() {
|
||||
var line = super.export_for_printing(...arguments);
|
||||
line.l10n_in_hsn_code = this.get_product().l10n_in_hsn_code;
|
||||
return line;
|
||||
}
|
||||
}
|
||||
Registries.Model.extend(Orderline, L10nInOrderline);
|
||||
|
||||
});
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<templates id="template" xml:space="preserve">
|
||||
<t t-name="OrderReceipt" t-inherit="point_of_sale.OrderReceipt" t-inherit-mode="extension" owl="1">
|
||||
<xpath expr="//div[hasclass('orderlines')]" position="before">
|
||||
<t t-if="receipt.partner and env.pos.company.country and env.pos.company.country.code == 'IN'">
|
||||
<div class="pos-receipt-center-align">
|
||||
<div><t t-esc="receipt.partner.name" /></div>
|
||||
<t t-if="receipt.partner.phone">
|
||||
<div>
|
||||
<span>Phone: </span>
|
||||
<t t-esc="receipt.partner.phone" />
|
||||
</div>
|
||||
</t>
|
||||
<br />
|
||||
</div>
|
||||
</t>
|
||||
</xpath>
|
||||
</t>
|
||||
|
||||
<t t-name="OrderLinesReceipt" t-inherit="point_of_sale.OrderLinesReceipt" t-inherit-mode="extension" owl="1">
|
||||
<xpath expr="//t[@t-foreach='receipt.orderlines']" position="inside">
|
||||
<t t-if="line.l10n_in_hsn_code and env.pos.company.country and env.pos.company.country.code == 'IN'">
|
||||
<div class="pos-receipt-left-padding">
|
||||
<span>HSN Code: </span>
|
||||
<t t-esc="line.l10n_in_hsn_code"/>
|
||||
</div>
|
||||
</t>
|
||||
</xpath>
|
||||
</t>
|
||||
</templates>
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
import { registry } from "@web/core/registry";
|
||||
import * as Chrome from "@point_of_sale/../tests/pos/tours/utils/chrome_util";
|
||||
import * as Dialog from "@point_of_sale/../tests/generic_helpers/dialog_util";
|
||||
import * as ProductScreen from "@point_of_sale/../tests/pos/tours/utils/product_screen_util";
|
||||
|
||||
registry.category("web_tour.tours").add("test_product_long_press_india", {
|
||||
steps: () =>
|
||||
[
|
||||
Chrome.startPoS(),
|
||||
Dialog.confirm("Open Register"),
|
||||
ProductScreen.longPressProduct("Test Product"),
|
||||
Dialog.is(),
|
||||
{
|
||||
content: "Check that VAT label is present in the product details popup",
|
||||
trigger: ".section-financials .vat-label:contains('GST')",
|
||||
},
|
||||
Chrome.endTour(),
|
||||
].flat(),
|
||||
});
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
import * as Chrome from "@point_of_sale/../tests/pos/tours/utils/chrome_util";
|
||||
import * as Dialog from "@point_of_sale/../tests/generic_helpers/dialog_util";
|
||||
import * as ProductScreen from "@point_of_sale/../tests/pos/tours/utils/product_screen_util";
|
||||
import * as PaymentScreen from "@point_of_sale/../tests/pos/tours/utils/payment_screen_util";
|
||||
import { registry } from "@web/core/registry";
|
||||
|
||||
export function addDocument(documentParams) {
|
||||
const steps = [];
|
||||
for (const values of documentParams) {
|
||||
steps.push(...ProductScreen.addOrderline(values.product, values.quantity));
|
||||
if (values.discount) {
|
||||
steps.push(ProductScreen.addDiscount(values.discount));
|
||||
}
|
||||
}
|
||||
steps.push(ProductScreen.clickPayButton());
|
||||
return steps;
|
||||
}
|
||||
|
||||
registry.category("web_tour.tours").add("test_l10n_in_hsn_summary_pos", {
|
||||
steps: () =>
|
||||
[
|
||||
Chrome.startPoS(),
|
||||
Dialog.confirm("Open Register"),
|
||||
|
||||
...addDocument([
|
||||
{ product: "product_1_1", quantity: "2" },
|
||||
{ product: "product_1_2", quantity: "1" },
|
||||
{ product: "product_1_3", quantity: "5" },
|
||||
{ product: "product_1_4", quantity: "2" },
|
||||
{ product: "product_1_5", quantity: "1" },
|
||||
{ product: "product_1_6", quantity: "5" },
|
||||
]),
|
||||
PaymentScreen.totalIs("5,129.0"),
|
||||
PaymentScreen.clickPaymentMethod("Bank"),
|
||||
PaymentScreen.remainingIs("0.0"),
|
||||
PaymentScreen.clickValidate(),
|
||||
{
|
||||
isActive: ["desktop"], // not rendered on mobile
|
||||
trigger:
|
||||
'.receipt-screen .l10n_in_hsn_summary_table tr:nth-child(3) td:nth-child(3):contains("57.50")',
|
||||
},
|
||||
{
|
||||
isActive: ["desktop"], // not rendered on mobile
|
||||
trigger:
|
||||
'.receipt-screen .l10n_in_hsn_summary_table tr:nth-child(3) td:nth-child(4):contains("57.50")',
|
||||
},
|
||||
{
|
||||
isActive: ["desktop"], // not rendered on mobile
|
||||
trigger:
|
||||
'.receipt-screen .l10n_in_hsn_summary_table tr:nth-child(4) td:nth-child(3):contains("207.00")',
|
||||
},
|
||||
{
|
||||
isActive: ["desktop"], // not rendered on mobile
|
||||
trigger:
|
||||
'.receipt-screen .l10n_in_hsn_summary_table tr:nth-child(4) td:nth-child(4):contains("207.00")',
|
||||
},
|
||||
].flat(),
|
||||
});
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from . import test_in_pos
|
||||
from . import test_hsn_summary
|
||||
from . import common
|
||||
from . import test_pos_flow
|
||||
from . import test_gstr_section
|
||||
from . import test_product_screen
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
from contextlib import contextmanager
|
||||
|
||||
from odoo.fields import Command
|
||||
from odoo.addons.point_of_sale.tests.common import TestPoSCommon
|
||||
from odoo.addons.account.tests.common import TestTaxCommon
|
||||
|
||||
|
||||
class TestInPosBase(TestPoSCommon):
|
||||
"""
|
||||
Base class for Indian GSTR and POS-related test cases.
|
||||
This class sets up the company, products, and configuration required
|
||||
for any test involving GSTR in a POS environment.
|
||||
"""
|
||||
@classmethod
|
||||
@TestTaxCommon.setup_country('in')
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
country_in_id = cls.env.ref("base.in").id
|
||||
cls.company_data["company"].write({
|
||||
"vat": "24AAGCC7144L6ZE",
|
||||
"state_id": cls.env.ref("base.state_in_gj").id,
|
||||
"street": "street1",
|
||||
"city": "city1",
|
||||
"zip": "123456",
|
||||
"country_id": country_in_id,
|
||||
"l10n_in_is_gst_registered": True,
|
||||
})
|
||||
cls.config = cls.basic_config
|
||||
cls.gst_5 = cls.env['account.chart.template'].ref('sgst_sale_5')
|
||||
cls.nil_rated = cls.env['account.chart.template'].ref('nil_rated_sale')
|
||||
|
||||
country_in = cls.env.ref('base.in')
|
||||
state_in_gj = cls.env.ref('base.state_in_gj')
|
||||
|
||||
cls.partner_a.write({
|
||||
'name': "Partner Intra State",
|
||||
'vat': '24ABCPM8965E1ZE',
|
||||
'state_id': state_in_gj.id,
|
||||
'country_id': country_in.id,
|
||||
'street': "Karansinhji Rd",
|
||||
'street2': "Karanpara",
|
||||
'city': "Rajkot",
|
||||
'zip': "360001",
|
||||
})
|
||||
|
||||
# Common product setup for POS tests
|
||||
cls._setup_products()
|
||||
|
||||
@classmethod
|
||||
def _setup_products(cls):
|
||||
"""Sets up products for POS testing with GST."""
|
||||
cls.product_a.write({
|
||||
'available_in_pos': True,
|
||||
'l10n_in_hsn_code': '1111',
|
||||
'list_price': 100,
|
||||
'taxes_id': [Command.set(cls.gst_5.ids)], # Tax: 5
|
||||
})
|
||||
cls.product_b.write({
|
||||
'available_in_pos': True,
|
||||
'l10n_in_hsn_code': '2222',
|
||||
'list_price': 200,
|
||||
'taxes_id': [Command.set(cls.gst_5.ids)], # Tax: 10
|
||||
})
|
||||
cls.product_c = cls.env['product.product'].create({
|
||||
'name': 'Product C',
|
||||
'available_in_pos': True,
|
||||
'list_price': 300,
|
||||
'taxes_id': [Command.set(cls.nil_rated.ids)], # Tax: 0
|
||||
})
|
||||
|
||||
@contextmanager
|
||||
def with_pos_session(self):
|
||||
"""Opens a new POS session and ensures it is closed properly."""
|
||||
session = self.open_new_session(0.0)
|
||||
yield session
|
||||
session.post_closing_cash_details(0.0)
|
||||
session.close_session_from_ui()
|
||||
|
||||
def _create_order(self, ui_data):
|
||||
"""Helper to create a POS order from UI data."""
|
||||
order_data = self.create_ui_order_data(**ui_data)
|
||||
results = self.env['pos.order'].sync_from_ui([order_data])
|
||||
return self.env['pos.order'].browse([o['id'] for o in results['pos.order']])
|
||||
|
||||
@classmethod
|
||||
def _create_categ_anglo(cls):
|
||||
# Stock Valuation support is currently not implemented for Indian localization.
|
||||
# Once support is added, this method override will be removed.
|
||||
return False
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
from odoo.addons.l10n_in_pos.tests.common import TestInPosBase
|
||||
from odoo.tests import tagged
|
||||
from datetime import date
|
||||
|
||||
TEST_DATE = date(2023, 5, 20)
|
||||
|
||||
|
||||
@tagged('post_install_l10n', 'post_install', '-at_install')
|
||||
class TestPOSGstrSection(TestInPosBase):
|
||||
|
||||
def test_b2cs_gstr_section_with_pos_order(self):
|
||||
with self.with_pos_session() as session:
|
||||
self._create_order({
|
||||
'pos_order_lines_ui_args': [
|
||||
(self.product_a, 2.0), # 2 units of product A
|
||||
(self.product_b, 2.0), # 2 units of product B
|
||||
],
|
||||
'payments': [(self.bank_pm1, 630.0)],
|
||||
})
|
||||
session.action_pos_session_closing_control()
|
||||
pos_entry_lines = session.move_id.line_ids
|
||||
for line in pos_entry_lines.filtered(lambda l: l.display_type in ('product, tax')):
|
||||
self.assertEqual(line.l10n_in_gstr_section, 'sale_b2cs')
|
||||
|
||||
def test_nil_rated_gstr_section_with_pos_order(self):
|
||||
with self.with_pos_session() as session:
|
||||
self._create_order({
|
||||
'pos_order_lines_ui_args': [
|
||||
(self.product_c, 3.0), # 3 units of product C
|
||||
],
|
||||
'payments': [(self.bank_pm1, 900.0)],
|
||||
'customer': self.partner_a,
|
||||
})
|
||||
session.action_pos_session_closing_control()
|
||||
pos_entry_lines = session.move_id.line_ids
|
||||
for line in pos_entry_lines.filtered(lambda l: l.display_type in ('product, tax')):
|
||||
self.assertEqual(line.l10n_in_gstr_section, 'sale_nil_rated')
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
from odoo.addons.account.tests.common import AccountTestInvoicingCommon
|
||||
from odoo.addons.l10n_in.tests.test_hsn_summary import TestL10nInHSNSummary
|
||||
from odoo.addons.point_of_sale.tests.test_frontend import TestTaxCommonPOS
|
||||
from odoo.tests import tagged
|
||||
|
||||
|
||||
@tagged('post_install', '-at_install', 'post_install_l10n')
|
||||
class TestL10nInHSNSummaryPos(TestTaxCommonPOS, TestL10nInHSNSummary):
|
||||
|
||||
@classmethod
|
||||
@AccountTestInvoicingCommon.setup_country('in')
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
|
||||
def create_base_line_product(self, base_line, **kwargs):
|
||||
# OVERRIDE 'point_of_sale'
|
||||
return super().create_base_line_product(base_line, **kwargs, l10n_in_hsn_code=base_line['l10n_in_hsn_code'])
|
||||
|
||||
def test_l10n_in_hsn_summary_pos(self):
|
||||
# We only do the first test just to be sure the code is not crashing.
|
||||
# There is no custom code in the POS for that so we suppose the results
|
||||
# are exactly the same.
|
||||
tests = self._test_l10n_in_hsn_summary_1()
|
||||
test1 = next(tests)
|
||||
self.ensure_products_on_document(test1[1], 'product_1')
|
||||
with self.with_new_session(user=self.pos_user):
|
||||
self.start_pos_tour('test_l10n_in_hsn_summary_pos')
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
from odoo.addons.account.tests.common import AccountTestInvoicingCommon
|
||||
from odoo.addons.point_of_sale.tests.test_generic_localization import TestGenericLocalization
|
||||
from odoo.tests import tagged
|
||||
|
||||
|
||||
@tagged('post_install', '-at_install', 'post_install_l10n')
|
||||
class TestGenericIN(TestGenericLocalization):
|
||||
|
||||
@classmethod
|
||||
@AccountTestInvoicingCommon.setup_country('in')
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
cls.state_in_gj = cls.env.ref('base.state_in_gj')
|
||||
cls.main_pos_config.company_id.write({
|
||||
'name': "Default Company",
|
||||
'state_id': cls.state_in_gj.id,
|
||||
'vat': "24AAGCC7144L6ZE",
|
||||
'street': "Khodiyar Chowk",
|
||||
'street2': "Sala Number 3",
|
||||
'city': "Amreli",
|
||||
'zip': "365220",
|
||||
})
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
from odoo.tests import tagged
|
||||
from .common import TestInPosBase
|
||||
|
||||
|
||||
@tagged('post_install_l10n', 'post_install', '-at_install')
|
||||
class TestPosFlow(TestInPosBase):
|
||||
"""
|
||||
Test class for GSTR-related POS functionality.
|
||||
"""
|
||||
|
||||
def test_invoice_order_after_session_closed(self):
|
||||
"""Test that an order can be invoiced after its session is closed.
|
||||
Scenario:
|
||||
1. Create a POS session and two orders:
|
||||
- Order A: Not to be invoiced immediately.
|
||||
- Order B: To be invoiced immediately.
|
||||
2. Close the POS session.
|
||||
3. Ensure:
|
||||
- Both orders have `reversed_move_ids` unset.
|
||||
4. Assign a partner to Order A and invoice it AFTER the session is closed.
|
||||
- Confirm that `reversed_move_ids` is set accordingly.
|
||||
"""
|
||||
|
||||
with self.with_pos_session():
|
||||
# Create a POS order without an invoice, simulating basic sale and payment
|
||||
pos_order_going_to_invoice = self._create_order({
|
||||
'pos_order_lines_ui_args': [
|
||||
(self.product_a, 2.0), # 2 units of product A
|
||||
(self.product_b, 2.0), # 2 units of product B
|
||||
],
|
||||
'payments': [(self.bank_pm1, 630.0)], # Payment of 630 through bank payment method
|
||||
})
|
||||
# Create a POS order with an invoice and a linked customer
|
||||
pos_order_with_invoice = self._create_order({
|
||||
'pos_order_lines_ui_args': [
|
||||
(self.product_a, 3.0), # 3 units of product A
|
||||
(self.product_b, 3.0), # 3 units of product B
|
||||
],
|
||||
'payments': [(self.bank_pm1, 945.0)], # Payment of 945 through bank payment method
|
||||
'customer': self.partner_a,
|
||||
})
|
||||
|
||||
# Initial state: no reversal moves for both orders
|
||||
self.assertFalse(pos_order_going_to_invoice.reversed_move_ids,
|
||||
"Order with 'to_invoice' = False should have no reversal moves after session is closed.")
|
||||
self.assertFalse(pos_order_with_invoice.reversed_move_ids,
|
||||
"Immediate invoiced order should have no reversal moves after session is closed.")
|
||||
|
||||
# Now, set a partner and invoice the order after the session is closed
|
||||
# with self.with_pos_session() as session2:
|
||||
pos_order_going_to_invoice.partner_id = self.partner_a
|
||||
pos_order_going_to_invoice.action_pos_order_invoice()
|
||||
# session2.action_pos_session_closing_control()
|
||||
|
||||
# Confirm that reversal move(s) are now set
|
||||
reversal_moves = self.env['account.move'].search([('reversed_pos_order_id', '=', pos_order_going_to_invoice.id)])
|
||||
self.assertEqual(pos_order_going_to_invoice.reversed_move_ids, reversal_moves,
|
||||
"Reversal move should be set for the order invoiced after the session is closed.")
|
||||
self.assertInvoiceValues(reversal_moves, [
|
||||
{'product_id': self.product_a.id, 'l10n_in_hsn_code': '1111', 'product_uom_id': self.product_a.uom_id.id, 'debit': 200.0, 'credit': 0.0},
|
||||
{'product_id': self.product_b.id, 'l10n_in_hsn_code': '2222', 'product_uom_id': self.product_b.uom_id.id, 'debit': 400.0, 'credit': 0.0},
|
||||
{'product_id': False, 'l10n_in_hsn_code': False, 'product_uom_id': False, 'debit': 15.0, 'credit': 0.0},
|
||||
{'product_id': False, 'l10n_in_hsn_code': False, 'product_uom_id': False, 'debit': 15.0, 'credit': 0.0},
|
||||
{'product_id': False, 'l10n_in_hsn_code': False, 'product_uom_id': False, 'debit': 0.0, 'credit': 630.0},
|
||||
|
||||
], {
|
||||
'amount_untaxed': 0.0,
|
||||
'amount_tax': 0.0,
|
||||
'amount_total': 630.0,
|
||||
})
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
from odoo.addons.point_of_sale.tests.test_generic_localization import TestGenericLocalization
|
||||
from odoo.tests import tagged
|
||||
|
||||
|
||||
@tagged('post_install', '-at_install', 'post_install_l10n')
|
||||
class TestGenericIN(TestGenericLocalization):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
cls.main_pos_config.company_id.write({
|
||||
'country_id': cls.env.ref("base.in")
|
||||
})
|
||||
|
||||
def test_product_long_press_india(self):
|
||||
""" Test the long press on product to open the product info """
|
||||
self.main_pos_config.company_id.country_id.vat_label = 'Should stay GST even after editing vat_label'
|
||||
|
||||
self.env['product.product'].create({
|
||||
'name': 'Test Product',
|
||||
'list_price': 100,
|
||||
'available_in_pos': True,
|
||||
})
|
||||
self.main_pos_config.with_user(self.pos_user).open_ui()
|
||||
self.start_pos_tour('test_product_long_press_india')
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<odoo>
|
||||
<record id="view_pos_pos_form_inherit" model="ir.ui.view">
|
||||
<field name="name">pos.order.form.inherit</field>
|
||||
<field name="model">pos.order</field>
|
||||
<field name="inherit_id" ref="point_of_sale.view_pos_pos_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='lines']/list/field[@name='product_id']" position="after">
|
||||
<field name="l10n_in_hsn_code" optional="hide"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<record id="l10n_in_pos.product_template_view_form_normalized_pos" model="ir.ui.view">
|
||||
<field name="name">l10n_in_pos.product.template.view.form.normalized.inherit</field>
|
||||
<field name="model">product.template</field>
|
||||
<field name="inherit_id" ref="point_of_sale.product_template_view_form_normalized_pos"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='pos_categ_ids']" position="before">
|
||||
<field name="l10n_in_hsn_code" invisible="'IN' not in fiscal_country_codes or not l10n_in_is_gst_registered_enabled"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="l10n_in_pos.product_tree_hsn_code" model="ir.ui.view">
|
||||
<field name="name">l10n_in_pos.product.list.hsn_code.pos</field>
|
||||
<field name="model">product.product</field>
|
||||
<field name="inherit_id" ref="product.product_product_tree_view"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="type" position="after">
|
||||
<field name="l10n_in_hsn_code" string="HSN/SAC Code" optional="show"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_missing_hsn_product" model="ir.actions.act_window">
|
||||
<field name="name">Missing HSN Products</field>
|
||||
<field name="res_model">product.product</field>
|
||||
<field name="view_mode">kanban,list,form</field>
|
||||
<field name="domain">[('l10n_in_hsn_missing_in_pos', '=', True)]</field>
|
||||
<field name="help" type="html">
|
||||
<p class="o_view_nocontent_smiling_face">
|
||||
Create a new product variant
|
||||
</p>
|
||||
<p>
|
||||
You must define an HSN for every product you sell through
|
||||
the point of sale interface.
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
<?xml version="1.0"?>
|
||||
<odoo>
|
||||
<record id="res_config_settings_view_form_l10n_in_pos_inherit" model="ir.ui.view">
|
||||
<field name="name">res.config.settings.view.form.inherit.l10n_in_pos.view</field>
|
||||
<field name="model">res.config.settings</field>
|
||||
<field name="inherit_id" ref="point_of_sale.res_config_settings_view_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//setting[@id='payment_methods_new']" position="before">
|
||||
<div class="o_notification_alert alert alert-warning" role="alert" invisible="not is_kiosk_mode or country_code != 'IN'">
|
||||
<span>Please note that the kiosk for INR currency only works with Razorpay terminal</span>
|
||||
</div>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
|
|
@ -1,13 +1,15 @@
|
|||
[project]
|
||||
name = "odoo-bringout-oca-ocb-l10n_in_pos"
|
||||
version = "16.0.0"
|
||||
description = "Indian - Point of Sale - Odoo addon"
|
||||
description = "Indian - Point of Sale -
|
||||
Odoo addon
|
||||
"
|
||||
authors = [
|
||||
{ name = "Ernad Husremovic", email = "hernad@bring.out.ba" }
|
||||
]
|
||||
dependencies = [
|
||||
"odoo-bringout-oca-ocb-l10n_in>=16.0.0",
|
||||
"odoo-bringout-oca-ocb-point_of_sale>=16.0.0",
|
||||
"odoo-bringout-oca-ocb-l10n_in>=19.0.0",
|
||||
"odoo-bringout-oca-ocb-point_of_sale>=19.0.0",
|
||||
"requests>=2.25.1"
|
||||
]
|
||||
readme = "README.md"
|
||||
|
|
@ -17,7 +19,7 @@ classifiers = [
|
|||
"Intended Audience :: Developers",
|
||||
"License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)",
|
||||
"Programming Language :: Python :: 3",
|
||||
"Programming Language :: Python :: 3.11",
|
||||
"Programming Language :: Python :: 3.11",
|
||||
"Programming Language :: Python :: 3.12",
|
||||
"Topic :: Office/Business",
|
||||
]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue