[ADD] l10n_in_edi_ewaybill: Create Indian E-waybill from invoice/bill

This module creates E-waybill in two types
1) Based on E-invoice API:
    Generates the E-waybill using the Invoice Registration Number (IRN) that create by the E-invoice service
2) Direct using E-waybill API:
    Generates the E-waybill using E-waybill API

X-original-commit: 2374d127792b3412e0ffe62515499d5b8f8ba434
Part-of: odoo/odoo#109390
This commit is contained in:
Jigar Vaghela
2023-01-14 21:44:41 +01:00
committed by Josse Colpaert
parent 2c65d25e95
commit be311c72fc
21 changed files with 1808 additions and 1 deletions
+1 -1
View File
@@ -18,7 +18,7 @@ We use "Tera Software Limited" as GSP
Step 1: First you need to create an API username and password in the E-invoice portal.
Step 2: Switch to company related to that GST number
Step 3: Set that username and password in Odoo (Goto: Invoicing/Accounting -> Configration -> Settings -> Customer Invoices or find "E-invoice" in search bar)
Step 3: Set that username and password in Odoo (Goto: Invoicing/Accounting -> Configuration -> Settings -> Customer Invoices or find "E-invoice" in search bar)
Step 4: Repeat steps 1,2,3 for all GSTIN you have in odoo. If you have a multi-company with the same GST number then perform step 1 for the first company only.
For the creation of API username and password please ref this document: <https://service.odoo.co.in/einvoice_create_api_user>
+4
View File
@@ -0,0 +1,4 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import models
+39
View File
@@ -0,0 +1,39 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
{
"name": """Indian - E-waybill""",
"version": "1.03.00",
"icon": "/l10n_in/static/description/icon.png",
"category": "Accounting/Localizations/EDI",
"depends": [
"l10n_in_edi",
],
"description": """
Indian - E-waybill
====================================
To submit E-waybill through API to the government.
We use "Tera Software Limited" as GSP
Step 1: First you need to create an API username and password in the E-waybill portal.
Step 2: Switch to company related to that GST number
Step 3: Set that username and password in Odoo (Goto: Invoicing/Accounting -> Configration -> Settings -> Indian Electronic WayBill or find "E-waybill" in search bar)
Step 4: Repeat steps 1,2,3 for all GSTIN you have in odoo. If you have a multi-company with the same GST number then perform step 1 for the first company only.
""",
"data": [
"security/ir.model.access.csv",
"data/account_edi_data.xml",
"data/ewaybill_type_data.xml",
"views/account_move_views.xml",
"views/edi_pdf_report.xml",
"views/res_config_settings_views.xml",
],
"demo": [
"demo/demo_company.xml",
"demo/res_partner_demo.xml",
"demo/account_invoice_demo.xml",
],
"installable": True,
# not applicable when company is related to service industry so auto install is False
"auto_install": False,
"license": "LGPL-3",
}
+7
View File
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="edi_in_ewaybill_json_1_03" model="account.edi.format">
<field name="name">E-waybill (IN)</field>
<field name="code">in_ewaybill_1_03</field>
</record>
</odoo>
+75
View File
@@ -0,0 +1,75 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- Document Type -->
<record id="type_tax_invoice_sub_type_supply" model="l10n.in.ewaybill.type">
<field name="name">Tax Invoice</field>
<field name="code">INV</field>
<field name="sub_type">Supply</field>
<field name="sub_type_code">1</field>
<field name="allowed_supply_type">both</field>
<field name="active" eval="True"/>
</record>
<record id="type_tax_invoice_sub_type_export" model="l10n.in.ewaybill.type">
<field name="name">Tax Invoice</field>
<field name="code">INV</field>
<field name="sub_type">Export</field>
<field name="sub_type_code">3</field>
<field name="allowed_supply_type">out</field>
<field name="active" eval="True"/>
</record>
<record id="type_tax_invoice_sub_type_skd_ckd_lots" model="l10n.in.ewaybill.type">
<field name="name">Tax Invoice</field>
<field name="code">INV</field>
<field name="sub_type">SKD/CKD/Lots</field>
<field name="sub_type_code">9</field>
<field name="allowed_supply_type">both</field>
<field name="active" eval="True"/>
</record>
<record id="type_bill_of_supply_sub_type_supply" model="l10n.in.ewaybill.type">
<field name="name">Bill of Supply</field>
<field name="code">BIL</field>
<field name="sub_type">Supply</field>
<field name="sub_type_code">1</field>
<field name="allowed_supply_type">both</field>
<field name="active" eval="True"/>
</record>
<record id="type_bill_of_supply_sub_type_export" model="l10n.in.ewaybill.type">
<field name="name">Bill of Supply</field>
<field name="code">BIL</field>
<field name="sub_type">Export</field>
<field name="sub_type_code">3</field>
<field name="allowed_supply_type">out</field>
<field name="active" eval="True"/>
</record>
<record id="type_bill_of_supply_sub_type_skd_ckd_lots" model="l10n.in.ewaybill.type">
<field name="name">Bill of Supply</field>
<field name="code">BIL</field>
<field name="sub_type">SKD/CKD/Lots</field>
<field name="sub_type_code">9</field>
<field name="allowed_supply_type">both</field>
<field name="active" eval="True"/>
</record>
<record id="type_bill_of_entry_sub_type_import" model="l10n.in.ewaybill.type">
<field name="name">Bill of Entry</field>
<field name="code">BOE</field>
<field name="sub_type">Import</field>
<field name="sub_type_code">2</field>
<field name="allowed_supply_type">in</field>
<field name="active" eval="True"/>
</record>
<record id="type_bill_of_entry_sub_skd_ckd_lots" model="l10n.in.ewaybill.type">
<field name="name">Bill of Entry</field>
<field name="code">BOE</field>
<field name="sub_type">SKD/CKD/Lots</field>
<field name="sub_type_code">9</field>
<field name="allowed_supply_type">in</field>
<field name="active" eval="True"/>
</record>
</odoo>
@@ -0,0 +1,66 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<function model="account.journal" name="write">
<value model="account.journal"
eval="obj().search([
('type', '=', 'sale'),
('company_id', '=', ref('l10n_in_edi_ewaybill.demo_company_in_ewaybill'))], limit=1).ids"/>
<value eval="{'edi_format_ids': [(6,0,[ref('edi_in_ewaybill_json_1_03')])]}"/>
</function>
<!-- Demo of B2B (business-to-business) Taxable supplies made to other registered person.-->
<record id="demo_invoice_b2b_ewaybill" model="account.move">
<field name="move_type">out_invoice</field>
<field name="partner_id" ref="res_partner_registered_customer_ewaybill"/>
<field name="invoice_user_id" ref="base.user_demo"/>
<field name="invoice_payment_term_id" ref="account.account_payment_term_end_following_month"/>
<field name="invoice_date" eval="time.strftime('%Y-%m')+'-01'"/>
<field name="l10n_in_gst_treatment">regular</field>
<field name="l10n_in_type_id" ref="type_tax_invoice_sub_type_supply"/>
<field name="l10n_in_distance">20</field>
<field name="l10n_in_mode">1</field>
<field name="l10n_in_vehicle_no">GJ11OD1234</field>
<field name="l10n_in_vehicle_type">R</field>
<field name="journal_id" model="account.journal"
eval="obj().search([
('type', '=', 'sale'),
('company_id', '=', ref('l10n_in_edi_ewaybill.demo_company_in_ewaybill'))], limit=1).id"/>
<field name="invoice_line_ids" model="account.move.line" eval="[
(0, 0, {
'product_id': ref('product.product_product_8'),
'quantity': 2,
'price_unit': 40000.0,
'tax_ids': [(6, 0, obj().tax_ids.search([
('company_id', '=', ref('l10n_in_edi_ewaybill.demo_company_in_ewaybill')),
('type_tax_use', '=', 'sale'),
('amount','=', 28),
('tax_group_id', '=', ref('l10n_in.igst_group'))], limit=1).ids)]
}),
(0, 0, {
'product_id': ref('product.product_product_9'),
'quantity': 3,
'price_unit': 400.0,
'tax_ids': [(6, 0, obj().tax_ids.search([
('company_id', '=', ref('l10n_in_edi_ewaybill.demo_company_in_ewaybill')),
('type_tax_use', '=', 'sale'),
('amount','=', 18),
('tax_group_id', '=', ref('l10n_in.igst_group'))], limit=1).ids)]
}),
(0, 0, {
'product_id': ref('product.product_product_10'),
'quantity': 4,
'price_unit': 300.0,
'tax_ids': [(6, 0, obj().tax_ids.search([
('company_id', '=', ref('l10n_in_edi_ewaybill.demo_company_in_ewaybill')),
('type_tax_use', '=', 'sale'),
'|',
'&amp;',
('amount', '=', 18),
('tax_group_id', '=', ref('l10n_in.igst_group')),
'&amp;',
('tax_group_id', '=', ref('l10n_in.cess_group')),
('children_tax_ids.amount','=', 5)
], limit=2).ids)]
}),
]"/>
</record>
</odoo>
+34
View File
@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="partner_demo_company_in_ewaybill" model="res.partner">
<field name="name">E-Waybill Company</field>
<field name="vat">05AAACH6188F1ZM</field>
<field name="street">46B 49B, RAIPUR</field>
<field name="street2">BHAGWANPUR, ROORKEE</field>
<field name="city">Haridwar</field>
<field name="country_id" ref="base.in"/>
<field name="state_id" ref="base.state_in_uk"/>
<field name="zip">247667</field>
</record>
<record id="demo_company_in_ewaybill" model="res.company">
<field name="name">E-Waybill Company</field>
<field name="partner_id" ref="partner_demo_company_in_ewaybill"/>
<field name="l10n_in_edi_ewaybill_username">05AAACH6188F1ZM</field>
<field name="l10n_in_edi_ewaybill_password">abc123@@</field>
</record>
<function model="res.company" name="_onchange_country_id">
<value eval="[ref('demo_company_in_ewaybill')]"/>
</function>
<function model="res.users" name="write">
<value eval="[ref('base.user_root'), ref('base.user_admin'), ref('base.user_demo')]"/>
<value eval="{'company_ids': [(4, ref('demo_company_in_ewaybill'))]}"/>
</function>
<function model="account.chart.template" name="try_loading">
<value eval="[ref('l10n_in.indian_chart_template_standard')]"/>
<value model="res.company" eval="obj().env.ref('l10n_in_edi_ewaybill.demo_company_in_ewaybill')"/>
</function>
</odoo>
+18
View File
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="res_partner_registered_customer_ewaybill" model="res.partner">
<field name="name">Registered Customer (E-Waybill)</field>
<field eval="[(6, 0, [ref('l10n_in.res_partner_category_registered')])]" name="category_id"/>
<field name="is_company">1</field>
<field name="l10n_in_gst_treatment">regular</field>
<field name="street">19, Ground Floor</field>
<field name="street2">Survey Road</field>
<field name="city">Dehradun</field>
<field name="zip">248001</field>
<field name="state_id" ref="base.state_in_uk"/>
<field name="country_id" ref="base.in"/>
<field name="vat">05AAACH6605F1Z0</field>
</record>
</odoo>
@@ -0,0 +1,522 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * l10n_in_edi_ewaybill
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 15.0+e\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-01-06 21:57+0000\n"
"PO-Revision-Date: 2023-01-06 21:57+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: l10n_in_edi_ewaybill
#: code:addons/l10n_in_edi_ewaybill/models/ewaybill_type.py:0
#, python-format
msgid " (Sub-Type: %s)"
msgstr ""
#. module: l10n_in_edi_ewaybill
#: code:addons/l10n_in_edi_ewaybill/models/account_edi_format.py:0
#, python-format
msgid "%s number should be set and not more than 16 characters"
msgstr ""
#. module: l10n_in_edi_ewaybill
#: code:addons/l10n_in_edi_ewaybill/models/account_edi_format.py:0
#, python-format
msgid "- Document Type"
msgstr ""
#. module: l10n_in_edi_ewaybill
#: code:addons/l10n_in_edi_ewaybill/models/account_edi_format.py:0
#, python-format
msgid ""
"- Transport document number and date is required when Transportation Mode is"
" Rail,Air or Ship"
msgstr ""
#. module: l10n_in_edi_ewaybill
#: code:addons/l10n_in_edi_ewaybill/models/account_edi_format.py:0
#, python-format
msgid "- Transportation Mode"
msgstr ""
#. module: l10n_in_edi_ewaybill
#: code:addons/l10n_in_edi_ewaybill/models/account_edi_format.py:0
#, python-format
msgid "- Transporter is required when E-waybill is managed by transporter"
msgstr ""
#. module: l10n_in_edi_ewaybill
#: code:addons/l10n_in_edi_ewaybill/models/account_edi_format.py:0
#, python-format
msgid ""
"- Vehicle Number and Type is required when Transportation Mode is By Road"
msgstr ""
#. module: l10n_in_edi_ewaybill
#: model_terms:ir.ui.view,arch_db:l10n_in_edi_ewaybill.res_config_settings_view_form_inherit_l10n_in_edi_ewaybill
msgid ""
"<span class=\"fa fa-lg fa-building-o\" title=\"Values set here are company-"
"specific.\" aria-label=\"Values set here are company-specific.\" "
"groups=\"base.group_multi_company\" role=\"img\"/>"
msgstr ""
#. module: l10n_in_edi_ewaybill
#: model_terms:ir.ui.view,arch_db:l10n_in_edi_ewaybill.invoice_form_inherit_l10n_in_edi_ewaybill
msgid "<span>km</span>"
msgstr ""
#. module: l10n_in_edi_ewaybill
#: model_terms:ir.ui.view,arch_db:l10n_in_edi_ewaybill.l10n_in_einvoice_report_invoice_document_inherit
msgid "<strong>E-waybill Number:</strong>"
msgstr ""
#. module: l10n_in_edi_ewaybill
#: model_terms:ir.ui.view,arch_db:l10n_in_edi_ewaybill.l10n_in_einvoice_report_invoice_document_inherit
msgid "<strong>E-waybill Valid Till:</strong>"
msgstr ""
#. module: l10n_in_edi_ewaybill
#: code:addons/l10n_in_edi_ewaybill/models/account_edi_format.py:0
#, python-format
msgid ""
"A username and password still needs to be set or it's wrong for the "
"E-waybill(IN). It needs to be added and verify in the Settings."
msgstr ""
#. module: l10n_in_edi_ewaybill
#: model:ir.model.fields,field_description:l10n_in_edi_ewaybill.field_l10n_in_ewaybill_type__active
msgid "Active"
msgstr ""
#. module: l10n_in_edi_ewaybill
#: model:ir.model.fields.selection,name:l10n_in_edi_ewaybill.selection__account_move__l10n_in_mode__3
msgid "Air"
msgstr ""
#. module: l10n_in_edi_ewaybill
#: model:ir.model.fields,field_description:l10n_in_edi_ewaybill.field_l10n_in_ewaybill_type__allowed_supply_type
msgid "Allowed for supply type"
msgstr ""
#. module: l10n_in_edi_ewaybill
#: model:ir.model.fields.selection,name:l10n_in_edi_ewaybill.selection__account_move__l10n_in_mode__1
msgid "By Road"
msgstr ""
#. module: l10n_in_edi_ewaybill
#: model_terms:ir.ui.view,arch_db:l10n_in_edi_ewaybill.invoice_form_inherit_l10n_in_edi_ewaybill
msgid "Cancel Reason"
msgstr ""
#. module: l10n_in_edi_ewaybill
#: model:ir.model,name:l10n_in_edi_ewaybill.model_res_company
msgid "Companies"
msgstr ""
#. module: l10n_in_edi_ewaybill
#: model:ir.model,name:l10n_in_edi_ewaybill.model_res_config_settings
msgid "Config Settings"
msgstr ""
#. module: l10n_in_edi_ewaybill
#: model:ir.model.fields,field_description:l10n_in_edi_ewaybill.field_l10n_in_ewaybill_type__create_uid
msgid "Created by"
msgstr ""
#. module: l10n_in_edi_ewaybill
#: model:ir.model.fields,field_description:l10n_in_edi_ewaybill.field_l10n_in_ewaybill_type__create_date
msgid "Created on"
msgstr ""
#. module: l10n_in_edi_ewaybill
#: model:ir.model.fields,help:l10n_in_edi_ewaybill.field_account_bank_statement_line__l10n_in_transportation_doc_date
#: model:ir.model.fields,help:l10n_in_edi_ewaybill.field_account_move__l10n_in_transportation_doc_date
#: model:ir.model.fields,help:l10n_in_edi_ewaybill.field_account_payment__l10n_in_transportation_doc_date
msgid "Date on the transporter document"
msgstr ""
#. module: l10n_in_edi_ewaybill
#: model:ir.model.fields,field_description:l10n_in_edi_ewaybill.field_l10n_in_ewaybill_type__display_name
msgid "Display Name"
msgstr ""
#. module: l10n_in_edi_ewaybill
#: model:ir.model.fields,field_description:l10n_in_edi_ewaybill.field_account_bank_statement_line__l10n_in_distance
#: model:ir.model.fields,field_description:l10n_in_edi_ewaybill.field_account_move__l10n_in_distance
#: model:ir.model.fields,field_description:l10n_in_edi_ewaybill.field_account_payment__l10n_in_distance
msgid "Distance"
msgstr ""
#. module: l10n_in_edi_ewaybill
#: model:ir.model.fields,field_description:l10n_in_edi_ewaybill.field_account_bank_statement_line__l10n_in_transportation_doc_date
#: model:ir.model.fields,field_description:l10n_in_edi_ewaybill.field_account_move__l10n_in_transportation_doc_date
#: model:ir.model.fields,field_description:l10n_in_edi_ewaybill.field_account_payment__l10n_in_transportation_doc_date
msgid "Document Date"
msgstr ""
#. module: l10n_in_edi_ewaybill
#: model:ir.model.fields,field_description:l10n_in_edi_ewaybill.field_account_bank_statement_line__l10n_in_transportation_doc_no
#: model:ir.model.fields,field_description:l10n_in_edi_ewaybill.field_account_move__l10n_in_transportation_doc_no
#: model:ir.model.fields,field_description:l10n_in_edi_ewaybill.field_account_payment__l10n_in_transportation_doc_no
msgid "Document Number"
msgstr ""
#. module: l10n_in_edi_ewaybill
#: model:ir.model.fields,field_description:l10n_in_edi_ewaybill.field_account_bank_statement_line__l10n_in_type_id
#: model:ir.model.fields,field_description:l10n_in_edi_ewaybill.field_account_move__l10n_in_type_id
#: model:ir.model.fields,field_description:l10n_in_edi_ewaybill.field_account_payment__l10n_in_type_id
msgid "Document Type"
msgstr ""
#. module: l10n_in_edi_ewaybill
#: model:ir.model.fields,field_description:l10n_in_edi_ewaybill.field_res_company__l10n_in_edi_ewaybill_password
msgid "E-Waybill (IN) Password"
msgstr ""
#. module: l10n_in_edi_ewaybill
#: model:ir.model.fields,field_description:l10n_in_edi_ewaybill.field_res_company__l10n_in_edi_ewaybill_username
msgid "E-Waybill (IN) Username"
msgstr ""
#. module: l10n_in_edi_ewaybill
#: model:ir.model.fields,field_description:l10n_in_edi_ewaybill.field_res_company__l10n_in_edi_ewaybill_auth_validity
msgid "E-Waybill (IN) Valid Until"
msgstr ""
#. module: l10n_in_edi_ewaybill
#: model:ir.model,name:l10n_in_edi_ewaybill.model_l10n_in_ewaybill_type
msgid "E-Waybill Document Type"
msgstr ""
#. module: l10n_in_edi_ewaybill
#: code:addons/l10n_in_edi_ewaybill/models/account_move.py:0
#, python-format
msgid "E-waybill is already created"
msgstr ""
#. module: l10n_in_edi_ewaybill
#: model:ir.model.fields,field_description:l10n_in_edi_ewaybill.field_account_bank_statement_line__l10n_in_edi_ewaybill_direct_api
#: model:ir.model.fields,field_description:l10n_in_edi_ewaybill.field_account_move__l10n_in_edi_ewaybill_direct_api
#: model:ir.model.fields,field_description:l10n_in_edi_ewaybill.field_account_payment__l10n_in_edi_ewaybill_direct_api
msgid "E-waybill(IN) direct API"
msgstr ""
#. module: l10n_in_edi_ewaybill
#: model:ir.model,name:l10n_in_edi_ewaybill.model_account_edi_format
msgid "EDI format"
msgstr ""
#. module: l10n_in_edi_ewaybill
#: code:addons/l10n_in_edi_ewaybill/models/account_edi_format.py:0
#, python-format
msgid "Error"
msgstr ""
#. module: l10n_in_edi_ewaybill
#: code:addons/l10n_in_edi_ewaybill/models/account_edi_format.py:0
#, python-format
msgid "HSN code is not set in product %s"
msgstr ""
#. module: l10n_in_edi_ewaybill
#: model:ir.model.fields,field_description:l10n_in_edi_ewaybill.field_l10n_in_ewaybill_type__id
msgid "ID"
msgstr ""
#. module: l10n_in_edi_ewaybill
#: code:addons/l10n_in_edi_ewaybill/models/account_edi_format.py:0
#, python-format
msgid "Impossible to send the Ewaybill."
msgstr ""
#. module: l10n_in_edi_ewaybill
#: model:ir.model.fields.selection,name:l10n_in_edi_ewaybill.selection__l10n_in_ewaybill_type__allowed_supply_type__in
msgid "Incoming"
msgstr ""
#. module: l10n_in_edi_ewaybill
#: model:ir.model.fields.selection,name:l10n_in_edi_ewaybill.selection__l10n_in_ewaybill_type__allowed_supply_type__both
msgid "Incoming and Outgoing"
msgstr ""
#. module: l10n_in_edi_ewaybill
#: code:addons/l10n_in_edi_ewaybill/models/res_config_settings.py:0
#, python-format
msgid ""
"Incorrect username or password, or the GST number on company does not match."
msgstr ""
#. module: l10n_in_edi_ewaybill
#: model:ir.model.fields,field_description:l10n_in_edi_ewaybill.field_res_config_settings__l10n_in_edi_ewaybill_password
msgid "Indian EDI Stock password"
msgstr ""
#. module: l10n_in_edi_ewaybill
#: model:ir.model.fields,field_description:l10n_in_edi_ewaybill.field_res_config_settings__l10n_in_edi_ewaybill_username
msgid "Indian EDI Stock username"
msgstr ""
#. module: l10n_in_edi_ewaybill
#: model_terms:ir.ui.view,arch_db:l10n_in_edi_ewaybill.res_config_settings_view_form_inherit_l10n_in_edi_ewaybill
msgid "Indian Electronic WayBill"
msgstr ""
#. module: l10n_in_edi_ewaybill
#: code:addons/l10n_in_edi_ewaybill/models/account_edi_format.py:0
#, python-format
msgid "Invalid HSN Code (%s) in product %s"
msgstr ""
#. module: l10n_in_edi_ewaybill
#: code:addons/l10n_in_edi_ewaybill/models/account_move.py:0
#, python-format
msgid ""
"Invalid invoice configuration:\n"
"\n"
"%s"
msgstr ""
#. module: l10n_in_edi_ewaybill
#: model:ir.model,name:l10n_in_edi_ewaybill.model_account_move
msgid "Journal Entry"
msgstr ""
#. module: l10n_in_edi_ewaybill
#: model:ir.model.fields,field_description:l10n_in_edi_ewaybill.field_l10n_in_ewaybill_type____last_update
msgid "Last Modified on"
msgstr ""
#. module: l10n_in_edi_ewaybill
#: model:ir.model.fields,field_description:l10n_in_edi_ewaybill.field_l10n_in_ewaybill_type__write_uid
msgid "Last Updated by"
msgstr ""
#. module: l10n_in_edi_ewaybill
#: model:ir.model.fields,field_description:l10n_in_edi_ewaybill.field_l10n_in_ewaybill_type__write_date
msgid "Last Updated on"
msgstr ""
#. module: l10n_in_edi_ewaybill
#: model:ir.model.fields.selection,name:l10n_in_edi_ewaybill.selection__account_move__l10n_in_mode__0
msgid "Managed by Transporter"
msgstr ""
#. module: l10n_in_edi_ewaybill
#: model:ir.model.fields.selection,name:l10n_in_edi_ewaybill.selection__account_move__l10n_in_vehicle_type__o
msgid "ODC"
msgstr ""
#. module: l10n_in_edi_ewaybill
#: model_terms:ir.ui.view,arch_db:l10n_in_edi_ewaybill.res_config_settings_view_form_inherit_l10n_in_edi_ewaybill
msgid "Only check if you are in production."
msgstr ""
#. module: l10n_in_edi_ewaybill
#: model:ir.model.fields.selection,name:l10n_in_edi_ewaybill.selection__l10n_in_ewaybill_type__allowed_supply_type__out
msgid "Outgoing"
msgstr ""
#. module: l10n_in_edi_ewaybill
#: model_terms:ir.ui.view,arch_db:l10n_in_edi_ewaybill.res_config_settings_view_form_inherit_l10n_in_edi_ewaybill
msgid "Password"
msgstr ""
#. module: l10n_in_edi_ewaybill
#: model_terms:ir.ui.view,arch_db:l10n_in_edi_ewaybill.res_config_settings_view_form_inherit_l10n_in_edi_ewaybill
msgid "Production Environment"
msgstr ""
#. module: l10n_in_edi_ewaybill
#: model:ir.model.fields.selection,name:l10n_in_edi_ewaybill.selection__account_move__l10n_in_mode__2
msgid "Rail"
msgstr ""
#. module: l10n_in_edi_ewaybill
#: model:ir.model.fields.selection,name:l10n_in_edi_ewaybill.selection__account_move__l10n_in_vehicle_type__r
msgid "Regular"
msgstr ""
#. module: l10n_in_edi_ewaybill
#: model_terms:ir.ui.view,arch_db:l10n_in_edi_ewaybill.invoice_form_inherit_l10n_in_edi_ewaybill
msgid "Send E-waybill"
msgstr ""
#. module: l10n_in_edi_ewaybill
#: model_terms:ir.ui.view,arch_db:l10n_in_edi_ewaybill.res_config_settings_view_form_inherit_l10n_in_edi_ewaybill
msgid "Setup E-Waybill"
msgstr ""
#. module: l10n_in_edi_ewaybill
#: model_terms:ir.ui.view,arch_db:l10n_in_edi_ewaybill.res_config_settings_view_form_inherit_l10n_in_edi_ewaybill
msgid "Setup E-Waybill Service for this company"
msgstr ""
#. module: l10n_in_edi_ewaybill
#: model:ir.model.fields.selection,name:l10n_in_edi_ewaybill.selection__account_move__l10n_in_mode__4
msgid "Ship"
msgstr ""
#. module: l10n_in_edi_ewaybill
#: model:ir.model.fields,field_description:l10n_in_edi_ewaybill.field_account_bank_statement_line__l10n_in_edi_ewaybill_show_send_button
#: model:ir.model.fields,field_description:l10n_in_edi_ewaybill.field_account_move__l10n_in_edi_ewaybill_show_send_button
#: model:ir.model.fields,field_description:l10n_in_edi_ewaybill.field_account_payment__l10n_in_edi_ewaybill_show_send_button
msgid "Show Send E-waybill Button"
msgstr ""
#. module: l10n_in_edi_ewaybill
#: code:addons/l10n_in_edi_ewaybill/models/account_edi_format.py:0
#, python-format
msgid ""
"Somehow this E-waybill has been canceled in the government portal before. "
"You can verify by checking the details into the government "
"(https://ewaybillgst.gov.in/Others/EBPrintnew.asp)"
msgstr ""
#. module: l10n_in_edi_ewaybill
#: code:addons/l10n_in_edi_ewaybill/models/account_edi_format.py:0
#: code:addons/l10n_in_edi_ewaybill/models/account_edi_format.py:0
#, python-format
msgid ""
"Somehow this E-waybill has been generated in the government portal before. "
"You can verify by checking the invoice details into the government "
"(https://ewaybillgst.gov.in/Others/EBPrintnew.asp)"
msgstr ""
#. module: l10n_in_edi_ewaybill
#: model:ir.model.fields,field_description:l10n_in_edi_ewaybill.field_l10n_in_ewaybill_type__sub_type
msgid "Sub-type"
msgstr ""
#. module: l10n_in_edi_ewaybill
#: model:ir.model.fields,field_description:l10n_in_edi_ewaybill.field_l10n_in_ewaybill_type__sub_type_code
msgid "Sub-type Code"
msgstr ""
#. module: l10n_in_edi_ewaybill
#: code:addons/l10n_in_edi_ewaybill/models/account_edi_format.py:0
#, python-format
msgid ""
"The following information are missing on the invoice (see eWayBill tab):"
msgstr ""
#. module: l10n_in_edi_ewaybill
#: code:addons/l10n_in_edi_ewaybill/models/account_move.py:0
#, python-format
msgid ""
"To cancel E-waybill set cancel reason and remarks at E-waybill tab in: \n"
"%s"
msgstr ""
#. module: l10n_in_edi_ewaybill
#: model_terms:ir.ui.view,arch_db:l10n_in_edi_ewaybill.invoice_form_inherit_l10n_in_edi_ewaybill
msgid "Transaction Details"
msgstr ""
#. module: l10n_in_edi_ewaybill
#: model:ir.model.fields,help:l10n_in_edi_ewaybill.field_account_bank_statement_line__l10n_in_transportation_doc_no
#: model:ir.model.fields,help:l10n_in_edi_ewaybill.field_account_move__l10n_in_transportation_doc_no
#: model:ir.model.fields,help:l10n_in_edi_ewaybill.field_account_payment__l10n_in_transportation_doc_no
msgid ""
"Transport document number. If it is more than 15 chars, last 15 chars may be"
" entered"
msgstr ""
#. module: l10n_in_edi_ewaybill
#: model_terms:ir.ui.view,arch_db:l10n_in_edi_ewaybill.invoice_form_inherit_l10n_in_edi_ewaybill
msgid "Transportation Details"
msgstr ""
#. module: l10n_in_edi_ewaybill
#: model:ir.model.fields,field_description:l10n_in_edi_ewaybill.field_account_bank_statement_line__l10n_in_mode
#: model:ir.model.fields,field_description:l10n_in_edi_ewaybill.field_account_move__l10n_in_mode
#: model:ir.model.fields,field_description:l10n_in_edi_ewaybill.field_account_payment__l10n_in_mode
msgid "Transportation Mode"
msgstr ""
#. module: l10n_in_edi_ewaybill
#: model:ir.model.fields,field_description:l10n_in_edi_ewaybill.field_account_bank_statement_line__l10n_in_transporter_id
#: model:ir.model.fields,field_description:l10n_in_edi_ewaybill.field_account_move__l10n_in_transporter_id
#: model:ir.model.fields,field_description:l10n_in_edi_ewaybill.field_account_payment__l10n_in_transporter_id
msgid "Transporter"
msgstr ""
#. module: l10n_in_edi_ewaybill
#: model:ir.model.fields,field_description:l10n_in_edi_ewaybill.field_l10n_in_ewaybill_type__name
msgid "Type"
msgstr ""
#. module: l10n_in_edi_ewaybill
#: model:ir.model.fields,field_description:l10n_in_edi_ewaybill.field_l10n_in_ewaybill_type__code
msgid "Type Code"
msgstr ""
#. module: l10n_in_edi_ewaybill
#: code:addons/l10n_in_edi_ewaybill/models/account_edi_format.py:0
#, python-format
msgid ""
"Unable to connect to the E-WayBill service.The web service may be temporary "
"down. Please try again in a moment."
msgstr ""
#. module: l10n_in_edi_ewaybill
#: model_terms:ir.ui.view,arch_db:l10n_in_edi_ewaybill.res_config_settings_view_form_inherit_l10n_in_edi_ewaybill
msgid "Username"
msgstr ""
#. module: l10n_in_edi_ewaybill
#: model:ir.model.fields,field_description:l10n_in_edi_ewaybill.field_account_bank_statement_line__l10n_in_vehicle_no
#: model:ir.model.fields,field_description:l10n_in_edi_ewaybill.field_account_move__l10n_in_vehicle_no
#: model:ir.model.fields,field_description:l10n_in_edi_ewaybill.field_account_payment__l10n_in_vehicle_no
msgid "Vehicle Number"
msgstr ""
#. module: l10n_in_edi_ewaybill
#: model:ir.model.fields,field_description:l10n_in_edi_ewaybill.field_account_bank_statement_line__l10n_in_vehicle_type
#: model:ir.model.fields,field_description:l10n_in_edi_ewaybill.field_account_move__l10n_in_vehicle_type
#: model:ir.model.fields,field_description:l10n_in_edi_ewaybill.field_account_payment__l10n_in_vehicle_type
msgid "Vehicle Type"
msgstr ""
#. module: l10n_in_edi_ewaybill
#: model_terms:ir.ui.view,arch_db:l10n_in_edi_ewaybill.res_config_settings_view_form_inherit_l10n_in_edi_ewaybill
msgid "Verify Username and Password"
msgstr ""
#. module: l10n_in_edi_ewaybill
#: code:addons/l10n_in_edi_ewaybill/models/account_move.py:0
#, python-format
msgid "You can only create E-waybill from posted invoice"
msgstr ""
#. module: l10n_in_edi_ewaybill
#: code:addons/l10n_in_edi_ewaybill/models/account_edi_format.py:0
#, python-format
msgid ""
"You need at least one product having \"Product Type\" as stockable or "
"consumable."
msgstr ""
#. module: l10n_in_edi_ewaybill
#: model_terms:ir.ui.view,arch_db:l10n_in_edi_ewaybill.invoice_form_inherit_l10n_in_edi_ewaybill
msgid "eWayBill"
msgstr ""
#. module: l10n_in_edi_ewaybill
#: code:addons/l10n_in_edi_ewaybill/models/account_edi_format.py:0
#, python-format
msgid "product is required to get HSN code"
msgstr ""
#. module: l10n_in_edi_ewaybill
#: code:addons/l10n_in_edi_ewaybill/models/account_edi_format.py:0
#, python-format
msgid "waiting For IRN generation To create E-waybill"
msgstr ""
+8
View File
@@ -0,0 +1,8 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import ewaybill_type
from . import res_company
from . import res_config_settings
from . import account_move
from . import account_edi_format
+607
View File
@@ -0,0 +1,607 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import re
import json
from datetime import timedelta
from odoo import models, fields, api, _
from odoo.tools import html_escape
from odoo.exceptions import AccessError
from odoo.addons.iap import jsonrpc
import logging
_logger = logging.getLogger(__name__)
DEFAULT_IAP_ENDPOINT = "https://l10n-in-edi.api.odoo.com"
DEFAULT_IAP_TEST_ENDPOINT = "https://l10n-in-edi-demo.api.odoo.com"
class AccountEdiFormat(models.Model):
_inherit = "account.edi.format"
def _l10n_in_edi_ewaybill_base_irn_or_direct(self, move):
"""
There is two type of api call to create E-waybill
1. base on IRN, IRN is number created when we do E-invoice
2. direct call, when E-invoice not aplicable or it"s credit not
"""
if move.move_type == "out_refund":
return "direct"
einvoice_in_edi_format = move.journal_id.edi_format_ids.filtered(lambda f: f.code == "in_einvoice_1_03")
return einvoice_in_edi_format and einvoice_in_edi_format._is_required_for_invoice(move) and "irn" or "direct"
def _is_compatible_with_journal(self, journal):
if self.code == "in_ewaybill_1_03":
return journal.type in ("sale", "purchase")
return super()._is_compatible_with_journal(journal)
def _is_enabled_by_default_on_journal(self, journal):
"""
It's sent with a button action on the invoice so it's disabled by default
"""
self.ensure_one()
if self.code == "in_ewaybill_1_03":
return False
return super()._is_enabled_by_default_on_journal(journal)
def _is_required_for_invoice(self, invoice):
self.ensure_one()
if self.code == "in_ewaybill_1_03":
return invoice.l10n_in_mode and invoice.is_invoice(include_receipts=True)
return super()._is_required_for_invoice(invoice)
def _needs_web_services(self):
self.ensure_one()
return self.code == "in_ewaybill_1_03" or super()._needs_web_services()
def _get_invoice_edi_content(self, move):
if self.code != "in_ewaybill_1_03":
return super()._get_invoice_edi_content(move)
base = self._l10n_in_edi_ewaybill_base_irn_or_direct(move)
if base == "irn":
json_dump = json.dumps(self._l10n_in_edi_irn_ewaybill_generate_json(move))
else:
json_dump = json.dumps(self._l10n_in_edi_ewaybill_generate_json(move))
return json_dump.encode()
def _check_move_configuration(self, move):
if self.code != "in_ewaybill_1_03":
return super()._check_move_configuration(move)
error_message = []
if not move.l10n_in_type_id:
error_message.append(_("- Document Type"))
if not move.l10n_in_mode:
error_message.append(_("- Transportation Mode"))
elif move.l10n_in_mode == "0" and not move.l10n_in_transporter_id:
error_message.append(_("- Transporter is required when E-waybill is managed by transporter"))
elif move.l10n_in_mode == "1":
if not move.l10n_in_vehicle_no and move.l10n_in_vehicle_type:
error_message.append(_("- Vehicle Number and Type is required when Transportation Mode is By Road"))
elif move.l10n_in_mode in ("2", "3", "4"):
if not move.l10n_in_transportation_doc_no and move.l10n_in_transportation_doc_date:
error_message.append(_("- Transport document number and date is required when Transportation Mode is Rail,Air or Ship"))
if error_message:
error_message.insert(0, _("The following information are missing on the invoice (see eWayBill tab):"))
base = self._l10n_in_edi_ewaybill_base_irn_or_direct(move)
if base == "irn":
# already checked by E-invoice (l10n_in_edi) so no need to check
return error_message
is_purchase = move.is_purchase_document(include_receipts=True)
error_message += self._l10n_in_validate_partner(move.partner_id)
error_message += self._l10n_in_validate_partner(move.company_id.partner_id, is_company=True)
if not re.match("^.{1,16}$", is_purchase and move.ref or move.name):
error_message.append(_("%s number should be set and not more than 16 characters",
(is_purchase and "Bill Reference" or "Invoice")))
goods_line_is_available = False
for line in move.invoice_line_ids.filtered(lambda line: not (line.display_type or line.is_rounding_line or line.product_id.type == "service")):
goods_line_is_available = True
if line.product_id:
hsn_code = self._l10n_in_edi_extract_digits(line.product_id.l10n_in_hsn_code)
if not hsn_code:
error_message.append(_("HSN code is not set in product %s", line.product_id.name))
elif not re.match("^[0-9]+$", hsn_code):
error_message.append(_(
"Invalid HSN Code (%s) in product %s", hsn_code, line.product_id.name
))
else:
error_message.append(_("product is required to get HSN code"))
if not goods_line_is_available:
error_message.append(_('You need at least one product having "Product Type" as stockable or consumable.'))
if error_message:
error_message.insert(0, _("Impossible to send the Ewaybill."))
return error_message
def _post_invoice_edi(self, invoices):
if self.code != "in_ewaybill_1_03":
return super()._post_invoice_edi(invoices)
base = self._l10n_in_edi_ewaybill_base_irn_or_direct(invoices)
if base == "irn":
return self._l10n_in_edi_ewaybill_irn_post_invoice_edi(invoices)
else:
return self._l10n_in_edi_ewaybill_post_invoice_edi(invoices)
def _cancel_invoice_edi(self, invoices):
if self.code != "in_ewaybill_1_03":
return super()._cancel_invoice_edi(invoices)
response = {}
res = {}
ewaybill_response_json = invoices._get_l10n_in_edi_ewaybill_response_json()
cancel_json = {
"ewbNo": ewaybill_response_json.get("ewayBillNo") or ewaybill_response_json.get("EwbNo"),
"cancelRsnCode": int(invoices.l10n_in_edi_cancel_reason),
"CnlRem": invoices.l10n_in_edi_cancel_remarks,
}
response = self._l10n_in_edi_ewaybill_cancel(invoices.company_id, cancel_json)
if response.get("error"):
error = response["error"]
error_codes = [e.get("code") for e in error]
if "238" in error_codes:
# Invalid token eror then create new token and send generate request again.
# This happen when authenticate called from another odoo instance with same credentials (like. Demo/Test)
authenticate_response = self._l10n_in_edi_ewaybill_authenticate(invoices.company_id)
if not authenticate_response.get("error"):
error = []
response = self._l10n_in_edi_ewaybill_cancel(invoices.company_id, cancel_json)
if response.get("error"):
error = response["error"]
error_codes = [e.get("code") for e in error]
if "312" in error_codes:
# E-waybill is already canceled
# this happens when timeout from the Government portal but IRN is generated
error_message = "<br/>".join(["[%s] %s" % (e.get("code"), html_escape(e.get("message"))) for e in error])
error = []
response = {"data": ""}
odoobot = self.env.ref("base.partner_root")
invoices.message_post(author_id=odoobot.id, body=
"%s<br/>%s:<br/>%s" %(
_("Somehow this E-waybill has been canceled in the government portal before. You can verify by checking the details into the government (https://ewaybillgst.gov.in/Others/EBPrintnew.asp)"),
_("Error"),
error_message
)
)
if "no-credit" in error_codes:
res[invoices] = {
"success": False,
"error": self._l10n_in_edi_get_iap_buy_credits_message(invoices.company_id),
"blocking_level": "error",
}
elif error:
error_message = "<br/>".join(["[%s] %s" % (e.get("code"), html_escape(e.get("message"))) for e in error])
blocking_level = "error"
if "404" in error_codes:
blocking_level = "warning"
res[invoices] = {
"success": False,
"error": error_message,
"blocking_level": blocking_level,
}
if not response.get("error"):
json_dump = json.dumps(response.get("data"))
json_name = "%s_ewaybill_cancel.json" % (invoices.name.replace("/", "_"))
attachment = self.env["ir.attachment"].create({
"name": json_name,
"raw": json_dump.encode(),
"res_model": "account.move",
"res_id": invoices.id,
"mimetype": "application/json",
})
inv_res = {"success": True, "attachment": attachment}
res[invoices] = inv_res
return res
def _l10n_in_edi_ewaybill_irn_post_invoice_edi(self, invoices):
response = {}
res = {}
generate_json = self._l10n_in_edi_irn_ewaybill_generate_json(invoices)
response = self._l10n_in_edi_irn_ewaybill_generate(invoices.company_id, generate_json)
if response.get("error"):
error = response["error"]
error_codes = [e.get("code") for e in error]
if "1005" in error_codes:
# Invalid token eror then create new token and send generate request again.
# This happen when authenticate called from another odoo instance with same credentials (like. Demo/Test)
authenticate_response = self._l10n_in_edi_authenticate(invoices.company_id)
if not authenticate_response.get("error"):
error = []
response = self._l10n_in_edi_irn_ewaybill_generate(invoices.company_id, generate_json)
if response.get("error"):
error = response["error"]
error_codes = [e.get("code") for e in error]
if "4002" in error_codes:
# Get E-waybill by details in case of IRN is already generated
# this happens when timeout from the Government portal but E-waybill is generated
response = self._l10n_in_edi_irn_ewaybill_get(invoices.company_id, generate_json.get("Irn"))
if not response.get("error"):
error = []
odoobot = self.env.ref("base.partner_root")
invoices.message_post(author_id=odoobot.id, body=
_("Somehow this E-waybill has been generated in the government portal before. You can verify by checking the invoice details into the government (https://ewaybillgst.gov.in/Others/EBPrintnew.asp)")
)
if "no-credit" in error_codes:
res[invoices] = {
"success": False,
"error": self._l10n_in_edi_get_iap_buy_credits_message(invoices.company_id),
"blocking_level": "error",
}
elif error:
error_message = "<br/>".join(["[%s] %s" % (e.get("code"), html_escape(e.get("message"))) for e in error])
blocking_level = "error"
if "404" in error_codes or "waiting" in error_codes:
blocking_level = "warning"
res[invoices] = {
"success": False,
"error": error_message,
"blocking_level": blocking_level,
}
if not response.get("error"):
json_dump = json.dumps(response.get("data"))
json_name = "%s_irn_ewaybill.json" % (invoices.name.replace("/", "_"))
attachment = self.env["ir.attachment"].create({
"name": json_name,
"raw": json_dump.encode(),
"res_model": "account.move",
"res_id": invoices.id,
"mimetype": "application/json",
})
inv_res = {"success": True, "attachment": attachment}
res[invoices] = inv_res
return res
def _l10n_in_edi_irn_ewaybill_generate_json(self, invoice):
json_payload = {
"Irn": invoice._get_l10n_in_edi_response_json().get("Irn"),
"Distance": invoice.l10n_in_distance,
}
if invoice.l10n_in_mode == "0":
json_payload.update({
"TransId": invoice.l10n_in_transporter_id.vat,
"TransName": invoice.l10n_in_transporter_id.name,
})
elif invoice.l10n_in_mode == "1":
json_payload.update({
"TransMode": invoice.l10n_in_mode,
"VehNo": invoice.l10n_in_vehicle_no,
"VehType": invoice.l10n_in_vehicle_type,
})
elif invoice.l10n_in_mode in ("2", "3", "4"):
doc_date = invoice.l10n_in_transportation_doc_date
json_payload.update({
"TransMode": invoice.l10n_in_mode,
"TransDocDt": doc_date and doc_date.strftime("%d/%m/%Y") or False,
"TransDocNo": invoice.l10n_in_transportation_doc_no,
})
return json_payload
def _l10n_in_edi_ewaybill_post_invoice_edi(self, invoices):
response = {}
res = {}
generate_json = self._l10n_in_edi_ewaybill_generate_json(invoices)
response = self._l10n_in_edi_ewaybill_generate(invoices.company_id, generate_json)
if response.get("error"):
error = response["error"]
error_codes = [e.get("code") for e in error]
if "238" in error_codes:
# Invalid token eror then create new token and send generate request again.
# This happen when authenticate called from another odoo instance with same credentials (like. Demo/Test)
authenticate_response = self._l10n_in_edi_ewaybill_authenticate(invoices.company_id)
if not authenticate_response.get("error"):
error = []
response = self._l10n_in_edi_ewaybill_generate(invoices.company_id, generate_json)
if response.get("error"):
error = response["error"]
error_codes = [e.get("code") for e in error]
if "604" in error_codes:
# Get E-waybill by details in case of E-waybill is already generated
# this happens when timeout from the Government portal but E-waybill is generated
response = self._l10n_in_edi_ewaybill_get_by_consigner(
invoices.company_id, generate_json.get("docType"), generate_json.get("docNo"))
if not response.get("error"):
error = []
odoobot = self.env.ref("base.partner_root")
invoices.message_post(author_id=odoobot.id, body=
_("Somehow this E-waybill has been generated in the government portal before. You can verify by checking the invoice details into the government (https://ewaybillgst.gov.in/Others/EBPrintnew.asp)")
)
if "no-credit" in error_codes:
res[invoices] = {
"success": False,
"error": self._l10n_in_edi_get_iap_buy_credits_message(invoices.company_id),
"blocking_level": "error",
}
elif error:
error_message = "<br/>".join(["[%s] %s" % (e.get("code"), html_escape(e.get("message"))) for e in error])
blocking_level = "error"
if "404" in error_codes:
blocking_level = "warning"
res[invoices] = {
"success": False,
"error": error_message,
"blocking_level": blocking_level,
}
if not response.get("error"):
json_dump = json.dumps(response.get("data"))
json_name = "%s_ewaybill.json" % (invoices.name.replace("/", "_"))
attachment = self.env["ir.attachment"].create({
"name": json_name,
"raw": json_dump.encode(),
"res_model": "account.move",
"res_id": invoices.id,
"mimetype": "application/json",
})
inv_res = {"success": True, "attachment": attachment}
res[invoices] = inv_res
return res
def _get_l10n_in_edi_saler_buyer_party(self, move):
res = super()._get_l10n_in_edi_saler_buyer_party(move)
if move.is_purchase_document(include_receipts=True):
res = {
"seller_details": move.partner_id,
"dispatch_details": move._l10n_in_get_shipping_partner(),
"buyer_details": move.company_id.partner_id,
"ship_to_details": move._l10n_in_get_warehouse_address() or move.company_id.partner_id,
}
return res
def _l10n_in_edi_ewaybill_generate_json(self, invoices):
def get_transaction_type(seller_details, dispatch_details, buyer_details, ship_to_details):
"""
1 - Regular
2 - Bill To - Ship To
3 - Bill From - Dispatch From
4 - Combination of 2 and 3
"""
if seller_details != dispatch_details and buyer_details != ship_to_details:
return 4
elif seller_details != dispatch_details:
return 3
elif buyer_details != ship_to_details:
return 2
else:
return 1
def filter_invl_to_apply(invoice_line):
if invoice_line.product_id.type == "service":
return False
return True
saler_buyer = self._get_l10n_in_edi_saler_buyer_party(invoices)
seller_details = saler_buyer.get("seller_details")
dispatch_details = saler_buyer.get("dispatch_details")
buyer_details = saler_buyer.get("buyer_details")
ship_to_details = saler_buyer.get("ship_to_details")
sign = invoices.is_inbound() and -1 or 1
extract_digits = self._l10n_in_edi_extract_digits
tax_details = self._l10n_in_prepare_edi_tax_details(invoices, filter_invl_to_apply=filter_invl_to_apply)
tax_details_by_code = self._get_l10n_in_tax_details_by_line_code(tax_details.get("tax_details", {}))
invoice_line_tax_details = tax_details.get("invoice_line_tax_details")
json_payload = {
"supplyType": invoices.is_purchase_document(include_receipts=True) and "I" or "O",
"subSupplyType": invoices.l10n_in_type_id.sub_type_code,
"docType": invoices.l10n_in_type_id.code,
"transactionType": get_transaction_type(seller_details, dispatch_details, buyer_details, ship_to_details),
"transDistance": str(invoices.l10n_in_distance),
"docNo": invoices.is_purchase_document(include_receipts=True) and invoices.ref or invoices.name,
"docDate": invoices.date.strftime("%d/%m/%Y"),
"fromGstin": seller_details.commercial_partner_id.vat or "URP",
"fromTrdName": seller_details.commercial_partner_id.name,
"fromAddr1": dispatch_details.street or "",
"fromAddr2": dispatch_details.street2 or "",
"fromPlace": dispatch_details.city or "",
"fromPincode": dispatch_details.country_id.code == "IN" and int(extract_digits(dispatch_details.zip)) or "",
"fromStateCode": int(seller_details.state_id.l10n_in_tin) or "",
"actFromStateCode": dispatch_details.state_id.l10n_in_tin and int(dispatch_details.state_id.l10n_in_tin) or "",
"toGstin": buyer_details.commercial_partner_id.vat or "URP",
"toTrdName": buyer_details.commercial_partner_id.name,
"toAddr1": ship_to_details.street or "",
"toAddr2": ship_to_details.street2 or "",
"toPlace": ship_to_details.city or "",
"toPincode": int(extract_digits(ship_to_details.zip)),
"actToStateCode": int(ship_to_details.state_id.l10n_in_tin),
"toStateCode": invoices.l10n_in_state_id.l10n_in_tin and int(invoices.l10n_in_state_id.l10n_in_tin) or (
buyer_details.state_id.l10n_in_tin or int(buyer_details.state_id.l10n_in_tin) or ""
),
"itemList": [
self._get_l10n_in_edi_ewaybill_line_details(line, line_tax_details, sign)
for line, line_tax_details in invoice_line_tax_details.items()
],
"totalValue": self._l10n_in_round_value(tax_details.get("base_amount") * sign),
"cgstValue": self._l10n_in_round_value(tax_details_by_code.get("cgst_amount", 0.00) * sign),
"sgstValue": self._l10n_in_round_value(tax_details_by_code.get("sgst_amount", 0.00) * sign),
"igstValue": self._l10n_in_round_value(tax_details_by_code.get("igst_amount", 0.00) * sign),
"cessValue": self._l10n_in_round_value(tax_details_by_code.get("cess_amount", 0.00) * sign),
"cessNonAdvolValue": self._l10n_in_round_value(tax_details_by_code.get("cess_non_advol_amount", 0.00) * sign),
"otherValue": self._l10n_in_round_value(tax_details_by_code.get("other_amount", 0.00) * sign),
"totInvValue": self._l10n_in_round_value((tax_details.get("base_amount") + tax_details.get("tax_amount")) * sign),
}
is_overseas = invoices.l10n_in_gst_treatment in ("overseas", "special_economic_zone")
if invoices.is_purchase_document(include_receipts=True):
if is_overseas:
json_payload.update({"fromStateCode": 99})
if is_overseas and dispatch_details.state_id.country_id.code != "IN":
json_payload.update({
"actFromStateCode": 99,
"fromPincode": 999999,
})
else:
json_payload.update({
"actFromStateCode": dispatch_details.state_id.l10n_in_tin and int(dispatch_details.state_id.l10n_in_tin) or "",
"fromPincode": int(extract_digits(dispatch_details.zip)),
})
else:
if is_overseas:
json_payload.update({"toStateCode": 99})
if is_overseas and ship_to_details.state_id.country_id.code != "IN":
json_payload.update({
"actToStateCode": 99,
"toPincode": 999999,
})
else:
json_payload.update({
"actToStateCode": int(ship_to_details.state_id.l10n_in_tin),
"toPincode": int(extract_digits(ship_to_details.zip)),
})
if invoices.l10n_in_mode == "0":
json_payload.update({
"transporterId": invoices.l10n_in_transporter_id.vat or "",
"transporterName": invoices.l10n_in_transporter_id.name or "",
})
if invoices.l10n_in_mode in ("2", "3", "4"):
json_payload.update({
"transMode": invoices.l10n_in_mode,
"transDocNo": invoices.l10n_in_transporter_doc_no or "",
"transDocDate": invoices.l10n_in_transporter_doc_date and
invoices.l10n_in_transporter_doc_date.strftime("%d/%m/%Y") or "",
})
if invoices.l10n_in_mode == "1":
json_payload.update({
"transMode": invoices.l10n_in_mode,
"vehicleNo": invoices.l10n_in_vehicle_no or "",
"vehicleType": invoices.l10n_in_vehicle_type or "",
})
return json_payload
def _get_l10n_in_edi_ewaybill_line_details(self, line, line_tax_details, sign):
extract_digits = self._l10n_in_edi_extract_digits
tax_details_by_code = self._get_l10n_in_tax_details_by_line_code(line_tax_details.get("tax_details", {}))
line_details = {
"productName": line.product_id.name,
"hsnCode": extract_digits(line.product_id.l10n_in_hsn_code),
"productDesc": line.name,
"quantity": line.quantity,
"qtyUnit": line.product_id.uom_id.l10n_in_code and line.product_id.uom_id.l10n_in_code.split("-")[0] or "OTH",
"taxableAmount": self._l10n_in_round_value(line.balance * sign),
}
if tax_details_by_code.get("igst_rate"):
line_details.update({"igstRate": self._l10n_in_round_value(tax_details_by_code["igst_rate"])})
else:
line_details.update({
"cgstRate": self._l10n_in_round_value(tax_details_by_code.get("cgst_rate", 0.00)),
"sgstRate": self._l10n_in_round_value(tax_details_by_code.get("sgst_rate", 0.00)),
})
if tax_details_by_code.get("cess_rate"):
line_details.update({"cessRate": self._l10n_in_round_value(tax_details_by_code.get("cess_rate"))})
return line_details
#================================ E-invoice API methods ===========================
@api.model
def _l10n_in_edi_irn_ewaybill_generate(self, company, json_payload):
# IRN is created by E-invoice API call so waiting for it.
if not json_payload.get("Irn"):
return {"error": [{
"code": "waiting",
"message": _("waiting For IRN generation To create E-waybill")}
]}
token = self._l10n_in_edi_get_token(company)
if not token:
return self._l10n_in_edi_no_config_response()
params = {
"auth_token": token,
"json_payload": json_payload,
}
return self._l10n_in_edi_connect_to_server(company, url_path="/iap/l10n_in_edi/1/generate_ewaybill_by_irn", params=params)
@api.model
def _l10n_in_edi_irn_ewaybill_get(self, company, irn):
token = self._l10n_in_edi_get_token(company)
if not token:
return self._l10n_in_edi_no_config_response()
params = {
"auth_token": token,
"irn": irn,
}
return self._l10n_in_edi_connect_to_server(company, url_path="/iap/l10n_in_edi/1/get_ewaybill_by_irn", params=params)
#=============================== E-waybill API methods ===================================
@api.model
def _l10n_in_edi_ewaybill_no_config_response(self):
return {"error": [{
"code": "000",
"message": _(
"A username and password still needs to be set or it's wrong for the E-waybill(IN). "
"It needs to be added and verify in the Settings."
)}
]}
@api.model
def _l10n_in_edi_ewaybill_check_authentication(self, company):
sudo_company = company.sudo()
if sudo_company.l10n_in_edi_ewaybill_username and sudo_company._l10n_in_edi_ewaybill_token_is_valid():
return True
elif sudo_company.l10n_in_edi_ewaybill_username and sudo_company.l10n_in_edi_ewaybill_password:
authenticate_response = self._l10n_in_edi_ewaybill_authenticate(company)
if not authenticate_response.get("error"):
return True
return False
@api.model
def _l10n_in_edi_ewaybill_connect_to_server(self, company, url_path, params):
user_token = self.env["iap.account"].get("l10n_in_edi")
params.update({
"account_token": user_token.account_token,
"dbuuid": self.env["ir.config_parameter"].sudo().get_param("database.uuid"),
"username": company.sudo().l10n_in_edi_ewaybill_username,
"gstin": company.vat,
})
if company.sudo().l10n_in_edi_production_env:
default_endpoint = DEFAULT_IAP_ENDPOINT
else:
default_endpoint = DEFAULT_IAP_TEST_ENDPOINT
endpoint = self.env["ir.config_parameter"].sudo().get_param("l10n_in_edi_ewaybill.endpoint", default_endpoint)
url = "%s%s" % (endpoint, url_path)
try:
return jsonrpc(url, params=params, timeout=25)
except AccessError as e:
_logger.warning("Connection error: %s", e.args[0])
return {
"error": [{
"code": "access_error",
"message": _("Unable to connect to the E-WayBill service."
"The web service may be temporary down. Please try again in a moment.")
}]
}
@api.model
def _l10n_in_edi_ewaybill_authenticate(self, company):
params = {"password": company.sudo().l10n_in_edi_ewaybill_password}
response = self._l10n_in_edi_ewaybill_connect_to_server(
company, url_path="/iap/l10n_in_edi_ewaybill/1/authenticate", params=params
)
if response and response.get("status_cd") == "1":
company.sudo().l10n_in_edi_ewaybill_auth_validity = fields.Datetime.now() + timedelta(
hours=6, minutes=00, seconds=00)
return response
@api.model
def _l10n_in_edi_ewaybill_generate(self, company, json_payload):
is_authenticated = self._l10n_in_edi_ewaybill_check_authentication(company)
if not is_authenticated:
return self._l10n_in_edi_ewaybill_no_config_response()
params = {"json_payload": json_payload}
return self._l10n_in_edi_ewaybill_connect_to_server(
company, url_path="/iap/l10n_in_edi_ewaybill/1/generate", params=params
)
@api.model
def _l10n_in_edi_ewaybill_cancel(self, company, json_payload):
is_authenticated = self._l10n_in_edi_ewaybill_check_authentication(company)
if not is_authenticated:
return self._l10n_in_edi_ewaybill_no_config_response()
params = {"json_payload": json_payload}
return self._l10n_in_edi_ewaybill_connect_to_server(
company, url_path="/iap/l10n_in_edi_ewaybill/1/cancel", params=params
)
@api.model
def _l10n_in_edi_ewaybill_get_by_consigner(self, company, document_type, document_number):
is_authenticated = self._l10n_in_edi_ewaybill_check_authentication(company)
if not is_authenticated:
return self._l10n_in_edi_ewaybill_no_config_response()
params = {"document_type": document_type, "document_number": document_number}
return self._l10n_in_edi_ewaybill_connect_to_server(
company, url_path="/iap/l10n_in_edi_ewaybill/1/getewaybillgeneratedbyconsigner", params=params
)
+123
View File
@@ -0,0 +1,123 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import json
from odoo import fields, models, api, _
from odoo.exceptions import UserError
class AccountMove(models.Model):
_inherit = "account.move"
# Transaction Details
l10n_in_type_id = fields.Many2one("l10n.in.ewaybill.type", "E-waybill Document Type", tracking=True)
# transportation details
l10n_in_distance = fields.Integer("Distance", tracking=True)
l10n_in_mode = fields.Selection([
("0", "Managed by Transporter"),
("1", "By Road"),
("2", "Rail"),
("3", "Air"),
("4", "Ship")],
string="Transportation Mode", copy=False, tracking=True)
# Vehicle Number and Type required when transportation mode is By Road.
l10n_in_vehicle_no = fields.Char("Vehicle Number", copy=False, tracking=True)
l10n_in_vehicle_type = fields.Selection([
("R", "Regular"),
("O", "ODC")],
string="Vehicle Type", copy=False, tracking=True)
# Document number and date required in case of transportation mode is Rail, Air or Ship.
l10n_in_transportation_doc_no = fields.Char(
string="E-waybill Document Number",
help="""Transport document number. If it is more than 15 chars, last 15 chars may be entered""",
copy=False, tracking=True)
l10n_in_transportation_doc_date = fields.Date(
string="Document Date",
help="Date on the transporter document",
copy=False,
tracking=True)
# transporter id required when transportation done by other party.
l10n_in_transporter_id = fields.Many2one("res.partner", "Transporter", copy=False, tracking=True)
# show and hide fields base on this
l10n_in_edi_ewaybill_direct_api = fields.Boolean(string="E-waybill(IN) direct API", compute="_compute_l10n_in_edi_ewaybill_direct")
l10n_in_edi_ewaybill_show_send_button = fields.Boolean(string="Show Send E-waybill Button", compute="_compute_l10n_in_edi_ewaybill_show_send_button")
@api.depends('state', 'edi_document_ids', 'edi_document_ids.state')
def _compute_l10n_in_edi_ewaybill_show_send_button(self):
edi_format = self.env.ref('l10n_in_edi_ewaybill.edi_in_ewaybill_json_1_03')
posted_moves = self.filtered(lambda x: x.is_invoice() and x.state == 'posted')
for move in posted_moves:
already_sent = move.edi_document_ids.filtered(lambda x: x.edi_format_id == edi_format and x.state in ('sent', 'to_cancel', 'to_send'))
if already_sent:
move.l10n_in_edi_ewaybill_show_send_button = False
else:
move.l10n_in_edi_ewaybill_show_send_button = True
(self - posted_moves).l10n_in_edi_ewaybill_show_send_button = False
@api.depends("l10n_in_gst_treatment")
def _compute_l10n_in_edi_ewaybill_direct(self):
for move in self:
base = self.env["account.edi.format"]._l10n_in_edi_ewaybill_base_irn_or_direct(move)
move.l10n_in_edi_ewaybill_direct_api = base == "direct"
@api.depends("edi_document_ids")
def _compute_l10n_in_edi_show_cancel(self):
super()._compute_l10n_in_edi_show_cancel()
for invoice in self:
if invoice.edi_document_ids.filtered(lambda i: i.edi_format_id.code == "in_ewaybill_1_03" and i.state in ("sent", "to_cancel", "cancelled")):
invoice.l10n_in_edi_show_cancel = True
def _get_l10n_in_edi_ewaybill_response_json(self):
self.ensure_one()
l10n_in_edi = self.edi_document_ids.filtered(lambda i: i.edi_format_id.code == "in_ewaybill_1_03"
and i.state in ("sent", "to_cancel"))
if l10n_in_edi and l10n_in_edi.attachment_id:
return json.loads(l10n_in_edi.attachment_id.raw.decode("utf-8"))
else:
return {}
def button_cancel_posted_moves(self):
"""Mark the edi.document related to this move to be canceled."""
reason_and_remarks_not_set = self.env["account.move"]
for move in self:
send_l10n_in_edi_ewaybill = move.edi_document_ids.filtered(lambda doc: doc.edi_format_id.code == "in_ewaybill_1_03")
# check submitted E-waybill does not have reason and remarks
# because it's needed to cancel E-waybill
if send_l10n_in_edi_ewaybill and (not move.l10n_in_edi_cancel_reason or not move.l10n_in_edi_cancel_remarks):
reason_and_remarks_not_set += move
if reason_and_remarks_not_set:
raise UserError(_(
"To cancel E-waybill set cancel reason and remarks at E-waybill tab in: \n%s",
("\n".join(reason_and_remarks_not_set.mapped("name"))),
))
return super().button_cancel_posted_moves()
def l10n_in_edi_ewaybill_send(self):
edi_format = self.env.ref('l10n_in_edi_ewaybill.edi_in_ewaybill_json_1_03')
edi_document_vals_list = []
for move in self:
if move.state != 'posted':
raise UserError(_("You can only create E-waybill from posted invoice"))
errors = edi_format._check_move_configuration(move)
if errors:
raise UserError(_("Invalid invoice configuration:\n\n%s") % '\n'.join(errors))
existing_edi_document = move.edi_document_ids.filtered(lambda x: x.edi_format_id == edi_format)
if existing_edi_document:
if existing_edi_document.state in ('sent', 'to_cancel'):
raise UserError(_("E-waybill is already created") % '\n'.join(errors))
existing_edi_document.write({
'state': 'to_send',
'attachment_id': False,
})
else:
edi_document_vals_list.append({
'edi_format_id': edi_format.id,
'move_id': move.id,
'state': 'to_send',
})
self.env['account.edi.document'].create(edi_document_vals_list)
self.env.ref('account_edi.ir_cron_edi_network')._trigger()
+32
View File
@@ -0,0 +1,32 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import fields, models, _
class EWayBillType(models.Model):
_name = "l10n.in.ewaybill.type"
_description = "E-Waybill Document Type"
name = fields.Char("Type")
code = fields.Char("Type Code")
sub_type = fields.Char("Sub-type")
sub_type_code = fields.Char("Sub-type Code")
allowed_supply_type = fields.Selection(
[
("both", "Incoming and Outgoing"),
("out", "Outgoing"),
("in", "Incoming"),
],
string="Allowed for supply type",
)
active = fields.Boolean("Active", default=True)
def name_get(self):
"""Show name and sub_type in name"""
result_dict = dict()
for ewaybill_type in self:
name = ewaybill_type.name
name += _(" (Sub-Type: %s)", ewaybill_type.sub_type)
result_dict[ewaybill_type.id] = name
return list(result_dict.items())
+18
View File
@@ -0,0 +1,18 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import fields, models
class ResCompany(models.Model):
_inherit = "res.company"
l10n_in_edi_ewaybill_username = fields.Char("E-Waybill (IN) Username", groups="base.group_system")
l10n_in_edi_ewaybill_password = fields.Char("E-Waybill (IN) Password", groups="base.group_system")
l10n_in_edi_ewaybill_auth_validity = fields.Datetime("E-Waybill (IN) Valid Until", groups="base.group_system")
def _l10n_in_edi_ewaybill_token_is_valid(self):
self.ensure_one()
if self.l10n_in_edi_ewaybill_auth_validity and self.l10n_in_edi_ewaybill_auth_validity > fields.Datetime.now():
return True
return False
+23
View File
@@ -0,0 +1,23 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import models, fields, _
from odoo.exceptions import UserError
from odoo.tools import html_escape
class ResConfigSettings(models.TransientModel):
_inherit = "res.config.settings"
l10n_in_edi_ewaybill_username = fields.Char("Indian EDI Stock username",
related="company_id.l10n_in_edi_ewaybill_username", readonly=False)
l10n_in_edi_ewaybill_password = fields.Char("Indian EDI Stock password",
related="company_id.l10n_in_edi_ewaybill_password", readonly=False)
def l10n_in_edi_ewaybill_test(self):
response = self.env["account.edi.format"]._l10n_in_edi_ewaybill_authenticate(self.company_id)
if response.get("error") or not self.company_id.sudo()._l10n_in_edi_ewaybill_token_is_valid():
error_message = _("Incorrect username or password, or the GST number on company does not match.")
if response.get("error"):
error_message = "\n".join(["[%s] %s" % (e.get("code"), html_escape(e.get("message"))) for e in response["error"]])
raise UserError(error_message)
+2
View File
@@ -0,0 +1,2 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
l10n_in_edi_ewaybill.access_l10n_in_ewaybill_type,access_l10n_in_ewaybill_type,l10n_in_edi_ewaybill.model_l10n_in_ewaybill_type,base.group_user,1,0,0,0
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 l10n_in_edi_ewaybill.access_l10n_in_ewaybill_type access_l10n_in_ewaybill_type l10n_in_edi_ewaybill.model_l10n_in_ewaybill_type base.group_user 1 0 0 0
@@ -0,0 +1,4 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import test_edi_ewaybill_json
@@ -0,0 +1,115 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo.addons.l10n_in_edi.tests.test_edi_json import TestEdiJson
from odoo.tests import tagged
@tagged("post_install_l10n", "post_install", "-at_install")
class TestEdiEwaybillJson(TestEdiJson):
def test_edi_json(self):
(self.invoice + self.invoice_full_discount + self.invoice_zero_qty).write({
"l10n_in_type_id": self.env.ref("l10n_in_edi_ewaybill.type_tax_invoice_sub_type_supply"),
"l10n_in_distance": 20,
"l10n_in_mode": "1",
"l10n_in_vehicle_no": "GJ11AA1234",
"l10n_in_vehicle_type": "R",
})
json_value = self.env["account.edi.format"]._l10n_in_edi_ewaybill_generate_json(self.invoice)
expected = {
"supplyType": "O",
"docType": "INV",
"subSupplyType": "1",
"transactionType": 1,
"transDistance": "20",
"transMode": "1",
"vehicleNo": "GJ11AA1234",
"vehicleType": "R",
"docNo": "INV/2019/00001",
"docDate": "01/01/2019",
"fromGstin": "36AABCT1332L011",
"fromTrdName": "company_1_data",
"fromAddr1": "Block no. 401",
"fromAddr2": "Street 2",
"fromPlace": "City 1",
"fromPincode": 500001,
"fromStateCode": 36,
"actFromStateCode": 36,
"toGstin": "36BBBFF5679L8ZR",
"toTrdName": "partner_a",
"toAddr1": "Block no. 401",
"toAddr2": "Street 2",
"toPlace": "City 2",
"toPincode": 500001,
"actToStateCode": 36,
"toStateCode": 36,
"itemList": [
{
"productName": "product_a",
"hsnCode": "01111",
"productDesc": "product_a",
"quantity": 1.0,
"qtyUnit": "UNT",
"taxableAmount": 900.0,
"cgstRate": 2.5,
"sgstRate": 2.5
},
{
"productName": "product_with_cess",
"hsnCode": "02222",
"productDesc": "product_with_cess",
"quantity": 1.0,
"qtyUnit": "UNT",
"taxableAmount": 900.0,
"cgstRate": 6.0,
"sgstRate": 6.0,
"cessRate": 5.0
}
],
"totalValue": 1800.0,
"cgstValue": 76.5,
"sgstValue": 76.5,
"igstValue": 0.0,
"cessValue": 45.0,
"cessNonAdvolValue": 1.59,
"otherValue": 0.0,
"totInvValue": 1999.59
}
self.assertDictEqual(json_value, expected, "Indian EDI send json value is not matched")
#=================================== Full discount test =====================================
json_value = self.env["account.edi.format"]._l10n_in_edi_ewaybill_generate_json(self.invoice_full_discount)
expected.update({
"docNo": "INV/2019/00002",
"itemList": [{
"productName": "product_a", "hsnCode": "01111", "productDesc": "product_a", "quantity": 1.0,
"qtyUnit": "UNT", "taxableAmount": 0.0, "cgstRate": 0.0, "sgstRate": 0.0
}],
"totalValue": 0.0,
"cgstValue": 0.0,
"sgstValue": 0.0,
"igstValue": 0.0,
"cessValue": 0.0,
"cessNonAdvolValue": 0.00,
"otherValue": 0.0,
"totInvValue": 0.0
})
self.assertDictEqual(json_value, expected, "Indian EDI with 100% discount sent json value is not matched")
#=================================== Zero quantity test =============================================
json_value = self.env["account.edi.format"]._l10n_in_edi_ewaybill_generate_json(self.invoice_zero_qty)
expected.update({
"docNo": "INV/2019/00003",
"itemList": [{
"productName": "product_a", "hsnCode": "01111", "productDesc": "product_a", "quantity": 0.0,
"qtyUnit": "UNT", "taxableAmount": 0.0, "cgstRate": 0.0, "sgstRate": 0.0
}],
"totalValue": 0.0,
"cgstValue": 0.0,
"sgstValue": 0.0,
"igstValue": 0.0,
"cessValue": 0.0,
"cessNonAdvolValue": 0.00,
"otherValue": 0.0,
"totInvValue": 0.0
})
self.assertDictEqual(json_value, expected, "Indian EDI with 0(zero) quantity sent json value is not matched")
+59
View File
@@ -0,0 +1,59 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="invoice_form_inherit_l10n_in_edi_ewaybill" model="ir.ui.view">
<field name="name">account.move.form.inherit.l10n.in.ewaybill</field>
<field name="model">account.move</field>
<field name="inherit_id" ref="account.view_move_form"/>
<field name="arch" type="xml">
<xpath expr="//button[@name='button_set_checked']" position="after">
<field name="l10n_in_edi_ewaybill_show_send_button" invisible="1"/>
<button name="l10n_in_edi_ewaybill_send" string="Send E-waybill" class="oe_highlight" type="object" groups="account.group_account_invoice" attrs="{'invisible' : [('l10n_in_edi_ewaybill_show_send_button','!=',True)]}"/>
</xpath>
<xpath expr="//notebook/page[@name='other_info']" position="before">
<page string="eWayBill" name="l10n_in_edi_ewaybill_page"
attrs="{'invisible':[('move_type', '=', 'entry'), ('country_code', '!=', 'IN')]}">
<field name="l10n_in_edi_ewaybill_direct_api" invisible="1"/>
<group name="ewaybill_group">
<group string="Transaction Details" name="Transaction_group"
attrs="{'invisible': [('l10n_in_edi_ewaybill_direct_api', '!=', True)]}">
<field name="l10n_in_type_id"
attrs="{'invisible': [
('move_type','in',('in_invoice','in_refund','in_receipt'))]}"
domain="[('allowed_supply_type','in',('in','both'))]"/>
<field name="l10n_in_type_id"
attrs="{'invisible': [
('move_type','in',('out_invoice','out_refund','out_receipt'))]}"
domain="[('allowed_supply_type','in',('out','both'))]"/>
</group>
<group string="Transportation Details" name="transportation_group">
<field name="l10n_in_mode"/>
<label for="l10n_in_distance"/>
<div class="o_row" name="l10n_in_distance">
<field name="l10n_in_distance"/>
<span>km</span>
</div>
<field name="l10n_in_vehicle_type"
attrs="{'invisible': [('l10n_in_mode','!=','1')], 'required': [('l10n_in_mode','=','1')]}"/>
<field name="l10n_in_vehicle_no"
attrs="{'invisible': [('l10n_in_mode','!=','1')], 'required': [('l10n_in_mode','=','1')]}"/>
<field name="l10n_in_transporter_id"
domain="[('vat','not in', ['', False]), ('country_id.code','=','IN')]"
attrs="{'invisible': [('l10n_in_mode','!=','0')], 'required': [('l10n_in_mode','=','0')]}"/>
<field name="l10n_in_transportation_doc_no"
attrs="{'invisible': [('l10n_in_mode','not in',('2','3','4'))], 'required': [('l10n_in_mode','in',('2','3','4'))]}"/>
<field name="l10n_in_transportation_doc_date"
attrs="{'invisible': [('l10n_in_mode','not in',('2','3','4'))], 'required': [('l10n_in_mode','in',('2','3','4'))]}"/>
</group>
<group string="Cancel Reason" attrs="{'invisible': ['|', '|',
('country_code', '!=', 'IN'),
('state', '!=', 'posted'),
('l10n_in_edi_show_cancel', '!=', True)]}">
<field name="l10n_in_edi_cancel_reason"/>
<field name="l10n_in_edi_cancel_remarks"/>
</group>
</group>
</page>
</xpath>
</field>
</record>
</odoo>
+20
View File
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<template id="l10n_in_einvoice_report_invoice_document_inherit" inherit_id="account.report_invoice_document">
<xpath expr="//div[@id='informations']" position="before">
<t t-set="l10n_in_ewaybill_json" t-value="o._get_l10n_in_edi_ewaybill_response_json()"/>
<div id="l10n_in_ewaybill_informations" class="row mt-4 mb-4">
<div class="col-auto col-3 mw-100 mb-2" t-if="l10n_in_ewaybill_json" name="ewaybill_number">
<strong>E-waybill Number:</strong>
<p t-if="'EwbNo' in l10n_in_ewaybill_json" class="m-0" t-esc="l10n_in_ewaybill_json['EwbNo']"/>
<p t-if="'ewayBillNo' in l10n_in_ewaybill_json" class="m-0" t-esc="l10n_in_ewaybill_json['ewayBillNo']"/>
</div>
<div class="col-auto col-3 mw-100 mb-2" t-if="l10n_in_ewaybill_json" name="ewaybill_validity">
<strong>E-waybill Valid Till:</strong>
<p t-if="'EwbValidTill' in l10n_in_ewaybill_json" class="m-0" t-esc="l10n_in_ewaybill_json['EwbValidTill']"/>
<p t-if="'validUpto' in l10n_in_ewaybill_json" class="m-0" t-esc="l10n_in_ewaybill_json['validUpto']"/>
</div>
</div>
</xpath>
</template>
</odoo>
@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="res_config_settings_view_form_inherit_l10n_in_edi_ewaybill" model="ir.ui.view">
<field name="name">res.config.settings.form.inherit.l10n_in_edi_ewaybill</field>
<field name="model">res.config.settings</field>
<field name="inherit_id" ref="account.res_config_settings_view_form"/>
<field name="arch" type="xml">
<app name="account" position="inside">
<block title="Indian Electronic Waybill" attrs="{'invisible': [('country_code', '!=', 'IN')]}">
<setting id="l10n_in_eway_iap" string="Setup Electronic Waybill" help="Check the documentation to get credentials." company_dependent="1">
<div class="content-group mt16">
<label for="l10n_in_edi_ewaybill_username" string="Username" class="col-3 col-lg-3 o_light_label"/>
<field name="l10n_in_edi_ewaybill_username" nolabel="1"/>
</div>
<div class="content-group">
<label for="l10n_in_edi_ewaybill_password" string="Password" class="col-3 col-lg-3 o_light_label" />
<field name="l10n_in_edi_ewaybill_password" password="True" nolabel="1"/>
</div>
<div class="content-group">
<label for="l10n_in_edi_production_env" string="Production Environment" class="col-3 col-lg-3 o_light_label"/>
<field name="l10n_in_edi_production_env" nolabel="1"/>
</div>
<div class='mt8'>
<button name="l10n_in_edi_ewaybill_test" icon="fa-arrow-right" type="object" string="Verify Username and Password" class="btn-link"/>
</div>
</setting>
</block>
</app>
</field>
</record>
</odoo>