mirror of
https://github.com/bringout/oca-financial.git
synced 2026-04-26 17:22:00 +02:00
Initial commit: OCA Financial packages (186 packages)
This commit is contained in:
commit
3e0e8473fb
8757 changed files with 947473 additions and 0 deletions
|
|
@ -0,0 +1,47 @@
|
|||
# Sales Stock Picking Invocing
|
||||
|
||||
Odoo addon: sale_stock_picking_invoicing
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
pip install odoo-bringout-oca-account-invoicing-sale_stock_picking_invoicing
|
||||
```
|
||||
|
||||
## Dependencies
|
||||
|
||||
This addon depends on:
|
||||
- sale_management
|
||||
- sale_stock
|
||||
- stock_picking_invoicing
|
||||
- stock_picking_invoice_link
|
||||
|
||||
## Manifest Information
|
||||
|
||||
- **Name**: Sales Stock Picking Invocing
|
||||
- **Version**: 16.0.1.0.1
|
||||
- **Category**: Warehouse Management
|
||||
- **License**: AGPL-3
|
||||
- **Installable**: True
|
||||
|
||||
## Source
|
||||
|
||||
Based on [OCA/account-invoicing](https://github.com/OCA/account-invoicing) branch 16.0, addon `sale_stock_picking_invoicing`.
|
||||
|
||||
## License
|
||||
|
||||
This package maintains the original AGPL-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
|
||||
- Install: doc/INSTALL.md
|
||||
- Usage: doc/USAGE.md
|
||||
- Configuration: doc/CONFIGURATION.md
|
||||
- Dependencies: doc/DEPENDENCIES.md
|
||||
- Troubleshooting: doc/TROUBLESHOOTING.md
|
||||
- FAQ: doc/FAQ.md
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
# Architecture
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
U[Users] -->|HTTP| V[Views and QWeb Templates]
|
||||
V --> C[Controllers]
|
||||
V --> W[Wizards – Transient Models]
|
||||
C --> M[Models and ORM]
|
||||
W --> M
|
||||
M --> R[Reports]
|
||||
DX[Data XML] --> M
|
||||
S[Security – ACLs and Groups] -. enforces .-> M
|
||||
|
||||
subgraph Sale_stock_picking_invoicing Module - sale_stock_picking_invoicing
|
||||
direction LR
|
||||
M:::layer
|
||||
W:::layer
|
||||
C:::layer
|
||||
V:::layer
|
||||
R:::layer
|
||||
S:::layer
|
||||
DX:::layer
|
||||
end
|
||||
|
||||
classDef layer fill:#eef8ff,stroke:#6ea8fe,stroke-width:1px
|
||||
```
|
||||
|
||||
Notes
|
||||
- Views include tree/form/kanban templates and report templates.
|
||||
- Controllers provide website/portal routes when present.
|
||||
- Wizards are UI flows implemented with `models.TransientModel`.
|
||||
- Data XML loads data/demo records; Security defines groups and access.
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
# Configuration
|
||||
|
||||
Refer to Odoo settings for sale_stock_picking_invoicing. Configure related models, access rights, and options as needed.
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
# Controllers
|
||||
|
||||
This module does not define custom HTTP controllers.
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
# Dependencies
|
||||
|
||||
This addon depends on:
|
||||
|
||||
- [sale_management](../../odoo-bringout-oca-ocb-sale_management)
|
||||
- [sale_stock](../../odoo-bringout-oca-ocb-sale_stock)
|
||||
- [stock_picking_invoicing](../../odoo-bringout-oca-account-invoicing-stock_picking_invoicing)
|
||||
- [stock_picking_invoice_link](../../odoo-bringout-oca-stock-logistics-workflow-stock_picking_invoice_link)
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
# FAQ
|
||||
|
||||
- Q: Which Odoo version? A: 16.0 (OCA/OCB packaged).
|
||||
- Q: How to enable? A: Start server with --addon sale_stock_picking_invoicing or install in UI.
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
# Install
|
||||
|
||||
```bash
|
||||
pip install odoo-bringout-oca-account-invoicing-sale_stock_picking_invoicing"
|
||||
# or
|
||||
uv pip install odoo-bringout-oca-account-invoicing-sale_stock_picking_invoicing"
|
||||
```
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
# Models
|
||||
|
||||
Detected core models and extensions in sale_stock_picking_invoicing.
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class res_company
|
||||
class res_config_settings
|
||||
class sale_order
|
||||
class sale_order_line
|
||||
class stock_move
|
||||
class stock_picking
|
||||
```
|
||||
|
||||
Notes
|
||||
- Classes show model technical names; fields omitted for brevity.
|
||||
- Items listed under _inherit are extensions of existing models.
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
# Overview
|
||||
|
||||
Packaged Odoo addon: sale_stock_picking_invoicing. Provides features documented in upstream Odoo 16 under this addon.
|
||||
|
||||
- Source: OCA/OCB 16.0, addon sale_stock_picking_invoicing
|
||||
- License: LGPL-3
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
# Reports
|
||||
|
||||
This module does not define custom reports.
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
# Security
|
||||
|
||||
This module does not define custom security rules or access controls beyond Odoo defaults.
|
||||
|
||||
Default Odoo security applies:
|
||||
- Base user access through standard groups
|
||||
- Model access inherited from dependencies
|
||||
- No custom row-level security rules
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
# Troubleshooting
|
||||
|
||||
- Ensure Python and Odoo environment matches repo guidance.
|
||||
- Check database connectivity and logs if startup fails.
|
||||
- Validate that dependent addons listed in DEPENDENCIES.md are installed.
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
# Usage
|
||||
|
||||
Start Odoo including this addon (from repo root):
|
||||
|
||||
```bash
|
||||
python3 scripts/nix_odoo_web_server.py --db-name mydb --addon sale_stock_picking_invoicing
|
||||
```
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
# Wizards
|
||||
|
||||
This module does not include UI wizards.
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
[project]
|
||||
name = "odoo-bringout-oca-account-invoicing-sale_stock_picking_invoicing"
|
||||
version = "16.0.0"
|
||||
description = "Sales Stock Picking Invocing - Odoo addon"
|
||||
authors = [
|
||||
{ name = "Ernad Husremovic", email = "hernad@bring.out.ba" }
|
||||
]
|
||||
dependencies = [
|
||||
"odoo-bringout-oca-account-invoicing-sale_management>=16.0.0",
|
||||
"odoo-bringout-oca-account-invoicing-sale_stock>=16.0.0",
|
||||
"odoo-bringout-oca-account-invoicing-stock_picking_invoicing>=16.0.0",
|
||||
"odoo-bringout-oca-account-invoicing-stock_picking_invoice_link>=16.0.0",
|
||||
"requests>=2.25.1"
|
||||
]
|
||||
readme = "README.md"
|
||||
requires-python = ">= 3.11"
|
||||
classifiers = [
|
||||
"Development Status :: 5 - Production/Stable",
|
||||
"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.12",
|
||||
"Topic :: Office/Business",
|
||||
]
|
||||
|
||||
[project.urls]
|
||||
homepage = "https://github.com/bringout/0"
|
||||
repository = "https://github.com/bringout/0"
|
||||
|
||||
[build-system]
|
||||
requires = ["hatchling"]
|
||||
build-backend = "hatchling.build"
|
||||
|
||||
[tool.hatch.metadata]
|
||||
allow-direct-references = true
|
||||
|
||||
[tool.hatch.build.targets.wheel]
|
||||
packages = ["sale_stock_picking_invoicing"]
|
||||
|
||||
[tool.rye]
|
||||
managed = true
|
||||
dev-dependencies = [
|
||||
"pytest>=8.4.1",
|
||||
]
|
||||
|
|
@ -0,0 +1,160 @@
|
|||
============================
|
||||
Sales Stock Picking Invocing
|
||||
============================
|
||||
|
||||
..
|
||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
!! This file is generated by oca-gen-addon-readme !!
|
||||
!! changes will be overwritten. !!
|
||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
!! source digest: sha256:2c14793fdb5a5bca2858a4db80020eff35109d87c35e92cfc63098e219719eaf
|
||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
|
||||
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
|
||||
:target: https://odoo-community.org/page/development-status
|
||||
:alt: Beta
|
||||
.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png
|
||||
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
|
||||
:alt: License: AGPL-3
|
||||
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Faccount--invoicing-lightgray.png?logo=github
|
||||
:target: https://github.com/OCA/account-invoicing/tree/16.0/sale_stock_picking_invoicing
|
||||
:alt: OCA/account-invoicing
|
||||
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
|
||||
:target: https://translation.odoo-community.org/projects/account-invoicing-16-0/account-invoicing-16-0-sale_stock_picking_invoicing
|
||||
:alt: Translate me on Weblate
|
||||
.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png
|
||||
:target: https://runboat.odoo-community.org/builds?repo=OCA/account-invoicing&target_branch=16.0
|
||||
:alt: Try me on Runboat
|
||||
|
||||
|badge1| |badge2| |badge3| |badge4| |badge5|
|
||||
|
||||
This module extends Stock Picking Invoicing implementation to Sale, you can define the 'Sale Invoicing Policy':
|
||||
|
||||
* If set to Sale Order, keep native Odoo behaviour for creation of invoices from Sale Orders.
|
||||
|
||||
* If set to Stock Picking, disallow creation of Invoices from Sale Orders for the cases where the Product Type are 'Product', in case of 'Service' still will be possible create from Sale Order.
|
||||
|
||||
For stock.moves, override price calculation that is present in stock_picking_invoicing, with the native Sale Order Line price calculation, same for the partner_id and other informations used to create the Invoice from Sale Order as such Payment Terms, Down Payments, Incoterm, Client Ref,etc by using sale methods to get data in order to avoid the necessity of 'glue modules' (small modules made just to avoid indirect dependencies), so in the case of any module include a new field in Invoice created by Sale this field also be include when created by Picking, for example the modules `Account Payment Sale`_ and `Sale Commission`_.
|
||||
|
||||
.. _`Account Payment Sale`: https://github.com/OCA/bank-payment/tree/14.0/account_payment_sale
|
||||
.. _`Sale Commission`: https://github.com/OCA/commission/tree/14.0/sale_commission
|
||||
|
||||
**Table of contents**
|
||||
|
||||
.. contents::
|
||||
:local:
|
||||
|
||||
Installation
|
||||
============
|
||||
|
||||
This module depends on:
|
||||
|
||||
* sale_management
|
||||
* sale_stock
|
||||
* stock_picking_invoicing
|
||||
* stock_picking_invoice_link
|
||||
|
||||
Configuration
|
||||
=============
|
||||
|
||||
Define 'Sale Invoicing Policy', if the invoice should be created from Sale Order or from Stock Picking, go to:
|
||||
|
||||
**Settings > Users & Companies > Companies**
|
||||
|
||||
or
|
||||
|
||||
**Sales > Configuration > Settings in Invoicing**
|
||||
|
||||
Usage
|
||||
=====
|
||||
|
||||
If 'Stock Picking' is choose as Policy the creation of Invoice from Sale Order works only for Service lines, in the case of Sale Order has Products and Service lines will be create two Invoices.
|
||||
|
||||
Known issues / Roadmap
|
||||
======================
|
||||
|
||||
* It is be possible reference multiple sale lines in only one invoice line, but there are a problem the field qty_invoiced in sale.order.line show the quantity of invoice line without consider, in this case, that the value is the sum of others sale lines https://github.com/odoo/odoo/blob/14.0/addons/sale/models/sale.py#L1230, what can make confuse the user about the real Invoiced Quantity, reference https://github.com/odoo/odoo/pull/77195
|
||||
|
||||
Changelog
|
||||
=========
|
||||
|
||||
16.0.1.0.0 (2025-01-14)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* Migration to version 16.0
|
||||
|
||||
15.0.1.0.0 (2024-10-25)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* Migration to version 15.0 .
|
||||
|
||||
14.0.1.0.0 (2024-03-12)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* [ADD] Module sale_stock_picking_invoicing based in l10n_br_sale_stock https://github.com/OCA/l10n-brazil/tree/14.0/l10n_br_sale_stock .
|
||||
|
||||
Bug Tracker
|
||||
===========
|
||||
|
||||
Bugs are tracked on `GitHub Issues <https://github.com/OCA/account-invoicing/issues>`_.
|
||||
In case of trouble, please check there if your issue has already been reported.
|
||||
If you spotted it first, help us to smash it by providing a detailed and welcomed
|
||||
`feedback <https://github.com/OCA/account-invoicing/issues/new?body=module:%20sale_stock_picking_invoicing%0Aversion:%2016.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
|
||||
|
||||
Do not contact contributors directly about support or help with technical issues.
|
||||
|
||||
Credits
|
||||
=======
|
||||
|
||||
Authors
|
||||
~~~~~~~
|
||||
|
||||
* Akretion
|
||||
|
||||
Contributors
|
||||
~~~~~~~~~~~~
|
||||
|
||||
* `Akretion <https://akretion.com>`_:
|
||||
|
||||
* Renato Lima <renato.lima@akretion.com.br>
|
||||
* Raphaël Valyi <raphael.valyi@akretion.com.br>
|
||||
* Magno Costa <magno.costa@akretion.com.br>
|
||||
|
||||
* `KMEE <https://www.kmee.com.br>`_:
|
||||
|
||||
* Gabriel Cardoso de Faria <gabriel.cardoso@kmee.com.br>
|
||||
|
||||
Other credits
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
The development of this module has been financially supported by:
|
||||
|
||||
* Aketion - www.akretion.com
|
||||
|
||||
Maintainers
|
||||
~~~~~~~~~~~
|
||||
|
||||
This module is maintained by the OCA.
|
||||
|
||||
.. image:: https://odoo-community.org/logo.png
|
||||
:alt: Odoo Community Association
|
||||
:target: https://odoo-community.org
|
||||
|
||||
OCA, or the Odoo Community Association, is a nonprofit organization whose
|
||||
mission is to support the collaborative development of Odoo features and
|
||||
promote its widespread use.
|
||||
|
||||
.. |maintainer-mbcosta| image:: https://github.com/mbcosta.png?size=40px
|
||||
:target: https://github.com/mbcosta
|
||||
:alt: mbcosta
|
||||
.. |maintainer-renatonlima| image:: https://github.com/renatonlima.png?size=40px
|
||||
:target: https://github.com/renatonlima
|
||||
:alt: renatonlima
|
||||
|
||||
Current `maintainers <https://odoo-community.org/page/maintainer-role>`__:
|
||||
|
||||
|maintainer-mbcosta| |maintainer-renatonlima|
|
||||
|
||||
This module is part of the `OCA/account-invoicing <https://github.com/OCA/account-invoicing/tree/16.0/sale_stock_picking_invoicing>`_ project on GitHub.
|
||||
|
||||
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
from . import models
|
||||
from . import wizards
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
# Copyright (C) 2013-Today - Akretion (<http://www.akretion.com>).
|
||||
# @author Renato Lima <renato.lima@akretion.com.br>
|
||||
# @author Raphael Valyi <raphael.valyi@akretion.com>
|
||||
# @author Magno Costa <magno.costa@akretion.com.br>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
{
|
||||
"name": "Sales Stock Picking Invocing",
|
||||
"category": "Warehouse Management",
|
||||
"license": "AGPL-3",
|
||||
"author": "Akretion, Odoo Community Association (OCA)",
|
||||
"website": "https://github.com/OCA/account-invoicing",
|
||||
"version": "16.0.1.0.1",
|
||||
"maintainers": ["mbcosta", "renatonlima"],
|
||||
"depends": [
|
||||
"sale_management",
|
||||
"sale_stock",
|
||||
"stock_picking_invoicing",
|
||||
"stock_picking_invoice_link",
|
||||
],
|
||||
"data": [
|
||||
"views/res_company_view.xml",
|
||||
"views/res_config_settings_view.xml",
|
||||
# Wizards
|
||||
"wizards/stock_invoice_onshipping_view.xml",
|
||||
],
|
||||
"demo": [
|
||||
"demo/sale_order_demo.xml",
|
||||
],
|
||||
"installable": True,
|
||||
"auto_install": False,
|
||||
}
|
||||
|
|
@ -0,0 +1,315 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<!--
|
||||
Copyright 2022-TODAY Akretion (http://www.akretion.com/)
|
||||
@author: Magno Costa <magno.costa@akretion.com.br>
|
||||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
-->
|
||||
<odoo noupdate="1">
|
||||
|
||||
<!-- Show partner_shipping_id in Sale Order -->
|
||||
<record
|
||||
id="group_sale_delivery_address_config_settings"
|
||||
model="res.config.settings"
|
||||
>
|
||||
<field name="group_sale_delivery_address">True</field>
|
||||
</record>
|
||||
|
||||
<function model="res.config.settings" name="execute">
|
||||
<value
|
||||
model="res.config.settings"
|
||||
search="[('id', '=',
|
||||
ref('group_sale_delivery_address_config_settings'))]"
|
||||
/>
|
||||
</function>
|
||||
|
||||
<!-- Show Incoterms in Sale Order and Invoice -->
|
||||
<record id="group_display_incoterm_config_settings" model="res.config.settings">
|
||||
<field name="group_display_incoterm">True</field>
|
||||
</record>
|
||||
|
||||
<function model="res.config.settings" name="execute">
|
||||
<value
|
||||
model="res.config.settings"
|
||||
search="[('id', '=',
|
||||
ref('group_display_incoterm_config_settings'))]"
|
||||
/>
|
||||
</function>
|
||||
|
||||
<!-- Test different Payment Terms -->
|
||||
<record id="base.res_partner_2" model="res.partner">
|
||||
<field
|
||||
name="property_payment_term_id"
|
||||
ref="account.account_payment_term_15days"
|
||||
/>
|
||||
</record>
|
||||
|
||||
<!-- Product is Service Type there is not Delivery Order in this cases,
|
||||
it's seems a mistake, fix here to use in the tests -->
|
||||
<record id="product.product_product_1" model="product.product">
|
||||
<field name="invoice_policy">order</field>
|
||||
</record>
|
||||
|
||||
<!-- Test with different shipping address -->
|
||||
<record id="res_partner_2_address" model="res.partner">
|
||||
<field eval="1" name="active" />
|
||||
<field name="is_company" eval="1" />
|
||||
<field name="name">Deco Addict - Delivery Address</field>
|
||||
<field name="parent_id" ref="base.res_partner_2" />
|
||||
<field
|
||||
eval="[(6, 0, [ref('base.res_partner_category_14')])]"
|
||||
name="category_id"
|
||||
/>
|
||||
<field name="street">77 Palos Verdes Rd</field>
|
||||
<field name="city">Pleasant Hill</field>
|
||||
<field name="state_id" ref='base.state_us_5' />
|
||||
<field name="zip">94521</field>
|
||||
<field name="country_id" ref="base.us" />
|
||||
<field name="type">delivery</field>
|
||||
<field name="email">deco.addict83@example.com</field>
|
||||
<field name="phone">(603)-996-3821</field>
|
||||
<field name="website">http://www.deco-addict.com</field>
|
||||
<field
|
||||
name="image_1920"
|
||||
type="base64"
|
||||
file="base/static/img/res_partner_2-image.png"
|
||||
/>
|
||||
</record>
|
||||
|
||||
<!-- Main Company - Different Shipping Address -->
|
||||
<record id="main_company-sale_order_1" model="sale.order">
|
||||
<field name="partner_id" ref="base.res_partner_2" />
|
||||
<field name="partner_invoice_id" ref="base.res_partner_2" />
|
||||
<field name="partner_shipping_id" ref="res_partner_2_address" />
|
||||
<field name="user_id" ref="base.user_admin" />
|
||||
<field name="pricelist_id" ref="product.list0" />
|
||||
<field name="payment_term_id" ref="account.account_payment_term_advance" />
|
||||
<field name="team_id" ref="sales_team.crm_team_1" />
|
||||
<field name="state">draft</field>
|
||||
<field name="company_id" ref="base.main_company" />
|
||||
<field
|
||||
name="note"
|
||||
>sale_stock_picking_invoicing - Different Delivery and Invoice Address 1</field>
|
||||
<field name="client_order_ref">Customer Ref Test 1</field>
|
||||
<field name="campaign_id" ref="utm.utm_campaign_christmas_special" />
|
||||
<field name="medium_id" ref="utm.utm_medium_banner" />
|
||||
<field name="source_id" ref="utm.utm_source_monster" />
|
||||
<field name="incoterm" ref="account.incoterm_FOB" />
|
||||
<field name="tag_ids" eval="[(4, ref('sales_team.categ_oppor1'))]" />
|
||||
</record>
|
||||
|
||||
<record id="main_company-sale_order_line_1_1" model="sale.order.line">
|
||||
<field name="order_id" ref="main_company-sale_order_1" />
|
||||
<field
|
||||
name="name"
|
||||
model="sale.order.line"
|
||||
eval="obj().env.ref('product.product_product_27').get_product_multiline_description_sale()"
|
||||
/>
|
||||
<field name="product_id" ref="product.product_product_27" />
|
||||
<field name="product_uom_qty">2</field>
|
||||
<field name="product_uom" ref="uom.product_uom_unit" />
|
||||
<field name="price_unit">500</field>
|
||||
</record>
|
||||
|
||||
<record id="main_company-sale_order_line_1_2" model="sale.order.line">
|
||||
<field name="order_id" ref="main_company-sale_order_1" />
|
||||
<field name="name">This is a Note 1</field>
|
||||
<field name="display_type">line_note</field>
|
||||
</record>
|
||||
|
||||
<record id="main_company-sale_order_line_1_3" model="sale.order.line">
|
||||
<field name="order_id" ref="main_company-sale_order_1" />
|
||||
<field name="name">This is a Section 1</field>
|
||||
<field name="display_type">line_section</field>
|
||||
</record>
|
||||
|
||||
<record id="main_company-sale_order_line_1_4" model="sale.order.line">
|
||||
<field name="order_id" ref="main_company-sale_order_1" />
|
||||
<field
|
||||
name="name"
|
||||
model="sale.order.line"
|
||||
eval="obj().env.ref('product.product_product_12').get_product_multiline_description_sale()"
|
||||
/>
|
||||
<field name="product_id" ref="product.product_product_12" />
|
||||
<field name="product_uom_qty">2</field>
|
||||
<field name="product_uom" ref="uom.product_uom_unit" />
|
||||
<field name="price_unit">500</field>
|
||||
</record>
|
||||
|
||||
<!-- Sale Order with Product and Service -->
|
||||
<record id="main_company-sale_order_2" model="sale.order">
|
||||
<field name="partner_id" ref="base.res_partner_2" />
|
||||
<field name="partner_invoice_id" ref="base.res_partner_2" />
|
||||
<field name="partner_shipping_id" ref="res_partner_2_address" />
|
||||
<field name="user_id" ref="base.user_admin" />
|
||||
<field name="pricelist_id" ref="product.list0" />
|
||||
<field name="payment_term_id" ref="account.account_payment_term_advance" />
|
||||
<field name="team_id" ref="sales_team.crm_team_1" />
|
||||
<field name="state">draft</field>
|
||||
<field name="company_id" ref="base.main_company" />
|
||||
<field name="note">sale_stock_picking_invoicing - Product and Service</field>
|
||||
<field name="client_order_ref">Customer Ref Test 2</field>
|
||||
<field name="campaign_id" ref="utm.utm_campaign_christmas_special" />
|
||||
<field name="medium_id" ref="utm.utm_medium_banner" />
|
||||
<field name="source_id" ref="utm.utm_source_monster" />
|
||||
<field name="incoterm" ref="account.incoterm_FOB" />
|
||||
<field
|
||||
name="tag_ids"
|
||||
eval="[(4, ref('sales_team.categ_oppor1')), (4, ref('sales_team.categ_oppor3'))]"
|
||||
/>
|
||||
</record>
|
||||
|
||||
<record id="main_company-sale_order_line_2_1" model="sale.order.line">
|
||||
<field name="order_id" ref="main_company-sale_order_2" />
|
||||
<field
|
||||
name="name"
|
||||
model="sale.order.line"
|
||||
eval="obj().env.ref('product.product_product_27').get_product_multiline_description_sale()"
|
||||
/>
|
||||
<field name="product_id" ref="product.product_product_27" />
|
||||
<field name="product_uom_qty">2</field>
|
||||
<field name="product_uom" ref="uom.product_uom_unit" />
|
||||
<field name="price_unit">500</field>
|
||||
</record>
|
||||
|
||||
<record id="main_company-sale_order_line_2_2" model="sale.order.line">
|
||||
<field name="order_id" ref="main_company-sale_order_2" />
|
||||
<field name="name">This is a Note 2</field>
|
||||
<field name="display_type">line_note</field>
|
||||
</record>
|
||||
|
||||
<record id="main_company-sale_order_line_2_3" model="sale.order.line">
|
||||
<field name="order_id" ref="main_company-sale_order_2" />
|
||||
<field name="name">This is a Section 2</field>
|
||||
<field name="display_type">line_section</field>
|
||||
</record>
|
||||
|
||||
<record id="main_company-sale_order_line_2_4" model="sale.order.line">
|
||||
<field name="order_id" ref="main_company-sale_order_2" />
|
||||
<field
|
||||
name="name"
|
||||
model="sale.order.line"
|
||||
eval="obj().env.ref('product.product_product_1').get_product_multiline_description_sale()"
|
||||
/>
|
||||
<field name="product_id" ref="product.product_product_1" />
|
||||
<field name="product_uom_qty">10</field>
|
||||
<field name="product_uom" ref="uom.product_uom_hour" />
|
||||
<field name="price_unit">100</field>
|
||||
</record>
|
||||
|
||||
<!-- Groupping Pickings Test -->
|
||||
<record id="main_company-sale_order_3" model="sale.order">
|
||||
<field name="partner_id" ref="base.res_partner_2" />
|
||||
<field name="partner_invoice_id" ref="base.res_partner_2" />
|
||||
<field name="partner_shipping_id" ref="base.res_partner_2" />
|
||||
<field name="user_id" ref="base.user_admin" />
|
||||
<field name="pricelist_id" ref="product.list0" />
|
||||
<field name="payment_term_id" ref="account.account_payment_term_advance" />
|
||||
<field name="team_id" ref="sales_team.crm_team_1" />
|
||||
<field name="state">draft</field>
|
||||
<field name="company_id" ref="base.main_company" />
|
||||
<field name="note">sale_stock_picking_invoicing - Grouping Pickings 3</field>
|
||||
<field name="client_order_ref">Customer Ref Test 3</field>
|
||||
<field name="campaign_id" ref="utm.utm_campaign_christmas_special" />
|
||||
<field name="medium_id" ref="utm.utm_medium_banner" />
|
||||
<field name="source_id" ref="utm.utm_source_monster" />
|
||||
<field name="incoterm" ref="account.incoterm_FOB" />
|
||||
<field name="tag_ids" eval="[(4, ref('sales_team.categ_oppor1'))]" />
|
||||
</record>
|
||||
|
||||
<record id="main_company-sale_order_line_3_1" model="sale.order.line">
|
||||
<field name="order_id" ref="main_company-sale_order_3" />
|
||||
<field
|
||||
name="name"
|
||||
model="sale.order.line"
|
||||
eval="obj().env.ref('product.product_product_27').get_product_multiline_description_sale()"
|
||||
/>
|
||||
<field name="product_id" ref="product.product_product_27" />
|
||||
<field name="product_uom_qty">2</field>
|
||||
<field name="product_uom" ref="uom.product_uom_unit" />
|
||||
<field name="price_unit">500</field>
|
||||
</record>
|
||||
|
||||
<record id="main_company-sale_order_line_3_2" model="sale.order.line">
|
||||
<field name="order_id" ref="main_company-sale_order_3" />
|
||||
<field name="name">This is a Note 3</field>
|
||||
<field name="display_type">line_note</field>
|
||||
</record>
|
||||
|
||||
<record id="main_company-sale_order_line_3_3" model="sale.order.line">
|
||||
<field name="order_id" ref="main_company-sale_order_3" />
|
||||
<field name="name">This is a Section 3</field>
|
||||
<field name="display_type">line_section</field>
|
||||
</record>
|
||||
|
||||
<record id="main_company-sale_order_line_3_4" model="sale.order.line">
|
||||
<field name="order_id" ref="main_company-sale_order_3" />
|
||||
<field
|
||||
name="name"
|
||||
model="sale.order.line"
|
||||
eval="obj().env.ref('product.product_product_12').get_product_multiline_description_sale()"
|
||||
/>
|
||||
<field name="product_id" ref="product.product_product_12" />
|
||||
<field name="product_uom_qty">2</field>
|
||||
<field name="product_uom" ref="uom.product_uom_unit" />
|
||||
<field name="price_unit">500</field>
|
||||
</record>
|
||||
|
||||
<!-- Groupping Pickings Test -->
|
||||
<record id="main_company-sale_order_4" model="sale.order">
|
||||
<field name="partner_id" ref="base.res_partner_2" />
|
||||
<field name="partner_invoice_id" ref="base.res_partner_2" />
|
||||
<field name="partner_shipping_id" ref="base.res_partner_2" />
|
||||
<field name="user_id" ref="base.user_admin" />
|
||||
<field name="pricelist_id" ref="product.list0" />
|
||||
<field name="payment_term_id" ref="account.account_payment_term_advance" />
|
||||
<field name="team_id" ref="sales_team.crm_team_1" />
|
||||
<field name="state">draft</field>
|
||||
<field name="company_id" ref="base.main_company" />
|
||||
<field name="note">sale_stock_picking_invoicing - Grouping Pickings 4</field>
|
||||
<field name="client_order_ref">Customer Ref Test 4</field>
|
||||
<field name="campaign_id" ref="utm.utm_campaign_christmas_special" />
|
||||
<field name="medium_id" ref="utm.utm_medium_banner" />
|
||||
<field name="source_id" ref="utm.utm_source_monster" />
|
||||
<field name="incoterm" ref="account.incoterm_FOB" />
|
||||
<field name="tag_ids" eval="[(4, ref('sales_team.categ_oppor1'))]" />
|
||||
</record>
|
||||
|
||||
<record id="main_company-sale_order_line_4_1" model="sale.order.line">
|
||||
<field name="order_id" ref="main_company-sale_order_4" />
|
||||
<field
|
||||
name="name"
|
||||
model="sale.order.line"
|
||||
eval="obj().env.ref('product.product_product_27').get_product_multiline_description_sale()"
|
||||
/>
|
||||
<field name="product_id" ref="product.product_product_27" />
|
||||
<field name="product_uom_qty">2</field>
|
||||
<field name="product_uom" ref="uom.product_uom_unit" />
|
||||
<field name="price_unit">500</field>
|
||||
</record>
|
||||
|
||||
<record id="main_company-sale_order_line_4_2" model="sale.order.line">
|
||||
<field name="order_id" ref="main_company-sale_order_4" />
|
||||
<field name="name">This is a Note 4</field>
|
||||
<field name="display_type">line_note</field>
|
||||
</record>
|
||||
|
||||
<record id="main_company-sale_order_line_4_3" model="sale.order.line">
|
||||
<field name="order_id" ref="main_company-sale_order_4" />
|
||||
<field name="name">This is a Section 4</field>
|
||||
<field name="display_type">line_section</field>
|
||||
</record>
|
||||
|
||||
<record id="main_company-sale_order_line_4_4" model="sale.order.line">
|
||||
<field name="order_id" ref="main_company-sale_order_4" />
|
||||
<field
|
||||
name="name"
|
||||
model="sale.order.line"
|
||||
eval="obj().env.ref('product.product_product_12').get_product_multiline_description_sale()"
|
||||
/>
|
||||
<field name="product_id" ref="product.product_product_12" />
|
||||
<field name="product_uom_qty">2</field>
|
||||
<field name="product_uom" ref="uom.product_uom_unit" />
|
||||
<field name="price_unit">500</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
|
|
@ -0,0 +1,104 @@
|
|||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * sale_stock_picking_invoicing
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server 16.0\n"
|
||||
"Report-Msgid-Bugs-To: \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: sale_stock_picking_invoicing
|
||||
#: model:ir.model,name:sale_stock_picking_invoicing.model_res_company
|
||||
msgid "Companies"
|
||||
msgstr "Kompanije"
|
||||
|
||||
#. module: sale_stock_picking_invoicing
|
||||
#: model:ir.model,name:sale_stock_picking_invoicing.model_res_config_settings
|
||||
msgid "Config Settings"
|
||||
msgstr "Postavke"
|
||||
|
||||
#. module: sale_stock_picking_invoicing
|
||||
#: model:ir.model.fields,field_description:sale_stock_picking_invoicing.field_stock_invoice_onshipping__deduct_down_payments
|
||||
msgid "Deduct down payments"
|
||||
msgstr "Odbij predujmove"
|
||||
|
||||
#. module: sale_stock_picking_invoicing
|
||||
#: model_terms:ir.ui.view,arch_db:sale_stock_picking_invoicing.sale_stock_picking_invoicing_res_config_settings_form
|
||||
msgid ""
|
||||
"Define if Invoice should be created from Sale Order or from Stock Picking"
|
||||
msgstr ""
|
||||
|
||||
#. module: sale_stock_picking_invoicing
|
||||
#: model:ir.model.fields,field_description:sale_stock_picking_invoicing.field_stock_invoice_onshipping__has_down_payments
|
||||
msgid "Has down payments"
|
||||
msgstr "Ima predujam"
|
||||
|
||||
#. module: sale_stock_picking_invoicing
|
||||
#: model:ir.model.fields,help:sale_stock_picking_invoicing.field_res_company__sale_invoicing_policy
|
||||
#: model:ir.model.fields,help:sale_stock_picking_invoicing.field_res_config_settings__sale_invoicing_policy
|
||||
msgid ""
|
||||
"If set to Sale Order, keep native Odoo behaviour for creation of invoices from Sale Orders.\n"
|
||||
"If set to Stock Picking, disallow creation of Invoices from Sale Orders for the cases where Product Type are 'Product', in case of 'Service' still will be possible create from Sale Order."
|
||||
msgstr ""
|
||||
|
||||
#. module: sale_stock_picking_invoicing
|
||||
#: model:ir.model.fields,field_description:sale_stock_picking_invoicing.field_res_company__sale_invoicing_policy
|
||||
#: model:ir.model.fields,field_description:sale_stock_picking_invoicing.field_res_config_settings__sale_invoicing_policy
|
||||
msgid "Sale Invoicing Policy"
|
||||
msgstr "Sale Invoicing Policy"
|
||||
|
||||
#. module: sale_stock_picking_invoicing
|
||||
#: model:ir.model.fields.selection,name:sale_stock_picking_invoicing.selection__res_company__sale_invoicing_policy__sale_order
|
||||
msgid "Sale Order"
|
||||
msgstr "Prodajni nalog"
|
||||
|
||||
#. module: sale_stock_picking_invoicing
|
||||
#: model:ir.model,name:sale_stock_picking_invoicing.model_sale_order
|
||||
msgid "Sales Order"
|
||||
msgstr "Prodajni nalog"
|
||||
|
||||
#. module: sale_stock_picking_invoicing
|
||||
#: model:ir.model,name:sale_stock_picking_invoicing.model_sale_order_line
|
||||
msgid "Sales Order Line"
|
||||
msgstr "Stavka prodajne narudžbe"
|
||||
|
||||
#. module: sale_stock_picking_invoicing
|
||||
#: model:ir.model,name:sale_stock_picking_invoicing.model_stock_invoice_onshipping
|
||||
msgid "Stock Invoice Onshipping"
|
||||
msgstr "Stock Invoice Onshipping"
|
||||
|
||||
#. module: sale_stock_picking_invoicing
|
||||
#: model:ir.model,name:sale_stock_picking_invoicing.model_stock_move
|
||||
msgid "Stock Move"
|
||||
msgstr "Skladišno kretanje"
|
||||
|
||||
#. module: sale_stock_picking_invoicing
|
||||
#: model:ir.model.fields.selection,name:sale_stock_picking_invoicing.selection__res_company__sale_invoicing_policy__stock_picking
|
||||
msgid "Stock Picking"
|
||||
msgstr "Preuzimanje u skladištu"
|
||||
|
||||
#. module: sale_stock_picking_invoicing
|
||||
#: model_terms:ir.ui.view,arch_db:sale_stock_picking_invoicing.sale_stock_picking_invoicing_res_config_settings_form
|
||||
msgid "This default value is applied to creation of Invoice."
|
||||
msgstr "This default value is applied to creation of Invoice."
|
||||
|
||||
#. module: sale_stock_picking_invoicing
|
||||
#: model:ir.model,name:sale_stock_picking_invoicing.model_stock_picking
|
||||
msgid "Transfer"
|
||||
msgstr "Prijenos"
|
||||
|
||||
#. module: sale_stock_picking_invoicing
|
||||
#. odoo-python
|
||||
#: code:addons/sale_stock_picking_invoicing/models/sale_order.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"When 'Sale Invoicing Policy' is defined as'Stock Picking' the Invoice can "
|
||||
"only be created from the Stock Picking, if necessary you can change in the "
|
||||
"Company or Sale Settings."
|
||||
msgstr ""
|
||||
|
|
@ -0,0 +1,118 @@
|
|||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * sale_stock_picking_invoicing
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server 16.0\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2025-02-09 23:06+0000\n"
|
||||
"Last-Translator: mymage <stefano.consolaro@mymage.it>\n"
|
||||
"Language-Team: none\n"
|
||||
"Language: it\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||
"X-Generator: Weblate 5.6.2\n"
|
||||
|
||||
#. module: sale_stock_picking_invoicing
|
||||
#: model:ir.model,name:sale_stock_picking_invoicing.model_res_company
|
||||
msgid "Companies"
|
||||
msgstr "Aziende"
|
||||
|
||||
#. module: sale_stock_picking_invoicing
|
||||
#: model:ir.model,name:sale_stock_picking_invoicing.model_res_config_settings
|
||||
msgid "Config Settings"
|
||||
msgstr "Impostazioni configurazione"
|
||||
|
||||
#. module: sale_stock_picking_invoicing
|
||||
#: model:ir.model.fields,field_description:sale_stock_picking_invoicing.field_stock_invoice_onshipping__deduct_down_payments
|
||||
msgid "Deduct down payments"
|
||||
msgstr "Dedurre acconti"
|
||||
|
||||
#. module: sale_stock_picking_invoicing
|
||||
#: model_terms:ir.ui.view,arch_db:sale_stock_picking_invoicing.sale_stock_picking_invoicing_res_config_settings_form
|
||||
msgid ""
|
||||
"Define if Invoice should be created from Sale Order or from Stock Picking"
|
||||
msgstr ""
|
||||
"Definire se la fattura deve essere creata dall'ordine di vendita o dal "
|
||||
"prelievo di magazzino"
|
||||
|
||||
#. module: sale_stock_picking_invoicing
|
||||
#: model:ir.model.fields,field_description:sale_stock_picking_invoicing.field_stock_invoice_onshipping__has_down_payments
|
||||
msgid "Has down payments"
|
||||
msgstr "Ha acconti"
|
||||
|
||||
#. module: sale_stock_picking_invoicing
|
||||
#: model:ir.model.fields,help:sale_stock_picking_invoicing.field_res_company__sale_invoicing_policy
|
||||
#: model:ir.model.fields,help:sale_stock_picking_invoicing.field_res_config_settings__sale_invoicing_policy
|
||||
msgid ""
|
||||
"If set to Sale Order, keep native Odoo behaviour for creation of invoices from Sale Orders.\n"
|
||||
"If set to Stock Picking, disallow creation of Invoices from Sale Orders for the cases where Product Type are 'Product', in case of 'Service' still will be possible create from Sale Order."
|
||||
msgstr ""
|
||||
"Se impostato su ordine di vendita, mantenere il comportamento nativo di Odoo "
|
||||
"per la creazione di fatture da ordini di vendita. \n"
|
||||
"Se impostato su prelievo di magazzino, non consente la creazione di fatture "
|
||||
"da ordini di vendita nei casi in cui il tipo di prodotto è 'Prodotto', in "
|
||||
"caso di 'Servizio' sarà comunque possibile crearle da ordine di vendita."
|
||||
|
||||
#. module: sale_stock_picking_invoicing
|
||||
#: model:ir.model.fields,field_description:sale_stock_picking_invoicing.field_res_company__sale_invoicing_policy
|
||||
#: model:ir.model.fields,field_description:sale_stock_picking_invoicing.field_res_config_settings__sale_invoicing_policy
|
||||
msgid "Sale Invoicing Policy"
|
||||
msgstr "Politica fatturazione vendite"
|
||||
|
||||
#. module: sale_stock_picking_invoicing
|
||||
#: model:ir.model.fields.selection,name:sale_stock_picking_invoicing.selection__res_company__sale_invoicing_policy__sale_order
|
||||
msgid "Sale Order"
|
||||
msgstr "Ordine di vendita"
|
||||
|
||||
#. module: sale_stock_picking_invoicing
|
||||
#: model:ir.model,name:sale_stock_picking_invoicing.model_sale_order
|
||||
msgid "Sales Order"
|
||||
msgstr "Ordine di vendita"
|
||||
|
||||
#. module: sale_stock_picking_invoicing
|
||||
#: model:ir.model,name:sale_stock_picking_invoicing.model_sale_order_line
|
||||
msgid "Sales Order Line"
|
||||
msgstr "Riga ordine di vendita"
|
||||
|
||||
#. module: sale_stock_picking_invoicing
|
||||
#: model:ir.model,name:sale_stock_picking_invoicing.model_stock_invoice_onshipping
|
||||
msgid "Stock Invoice Onshipping"
|
||||
msgstr "Fattura su spedizione"
|
||||
|
||||
#. module: sale_stock_picking_invoicing
|
||||
#: model:ir.model,name:sale_stock_picking_invoicing.model_stock_move
|
||||
msgid "Stock Move"
|
||||
msgstr "Movimento di magazzino"
|
||||
|
||||
#. module: sale_stock_picking_invoicing
|
||||
#: model:ir.model.fields.selection,name:sale_stock_picking_invoicing.selection__res_company__sale_invoicing_policy__stock_picking
|
||||
msgid "Stock Picking"
|
||||
msgstr "Prelievo di magazzino"
|
||||
|
||||
#. module: sale_stock_picking_invoicing
|
||||
#: model_terms:ir.ui.view,arch_db:sale_stock_picking_invoicing.sale_stock_picking_invoicing_res_config_settings_form
|
||||
msgid "This default value is applied to creation of Invoice."
|
||||
msgstr "Questo valore predefinito è applicato alla creazione della fattura."
|
||||
|
||||
#. module: sale_stock_picking_invoicing
|
||||
#: model:ir.model,name:sale_stock_picking_invoicing.model_stock_picking
|
||||
msgid "Transfer"
|
||||
msgstr "Trasferimento"
|
||||
|
||||
#. module: sale_stock_picking_invoicing
|
||||
#. odoo-python
|
||||
#: code:addons/sale_stock_picking_invoicing/models/sale_order.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"When 'Sale Invoicing Policy' is defined as'Stock Picking' the Invoice can "
|
||||
"only be created from the Stock Picking, if necessary you can change in the "
|
||||
"Company or Sale Settings."
|
||||
msgstr ""
|
||||
"Quando la \"Politica di fatturazione delle vendite\" è definita come "
|
||||
"\"Prelievo di magazzino\", la fattura può essere creata solo dal prelievo di "
|
||||
"magazzino; se necessario, è possibile apportare modifiche nelle Impostazioni "
|
||||
"aziendali o di vendita."
|
||||
|
|
@ -0,0 +1,104 @@
|
|||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * sale_stock_picking_invoicing
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server 16.0\n"
|
||||
"Report-Msgid-Bugs-To: \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: sale_stock_picking_invoicing
|
||||
#: model:ir.model,name:sale_stock_picking_invoicing.model_res_company
|
||||
msgid "Companies"
|
||||
msgstr ""
|
||||
|
||||
#. module: sale_stock_picking_invoicing
|
||||
#: model:ir.model,name:sale_stock_picking_invoicing.model_res_config_settings
|
||||
msgid "Config Settings"
|
||||
msgstr ""
|
||||
|
||||
#. module: sale_stock_picking_invoicing
|
||||
#: model:ir.model.fields,field_description:sale_stock_picking_invoicing.field_stock_invoice_onshipping__deduct_down_payments
|
||||
msgid "Deduct down payments"
|
||||
msgstr ""
|
||||
|
||||
#. module: sale_stock_picking_invoicing
|
||||
#: model_terms:ir.ui.view,arch_db:sale_stock_picking_invoicing.sale_stock_picking_invoicing_res_config_settings_form
|
||||
msgid ""
|
||||
"Define if Invoice should be created from Sale Order or from Stock Picking"
|
||||
msgstr ""
|
||||
|
||||
#. module: sale_stock_picking_invoicing
|
||||
#: model:ir.model.fields,field_description:sale_stock_picking_invoicing.field_stock_invoice_onshipping__has_down_payments
|
||||
msgid "Has down payments"
|
||||
msgstr ""
|
||||
|
||||
#. module: sale_stock_picking_invoicing
|
||||
#: model:ir.model.fields,help:sale_stock_picking_invoicing.field_res_company__sale_invoicing_policy
|
||||
#: model:ir.model.fields,help:sale_stock_picking_invoicing.field_res_config_settings__sale_invoicing_policy
|
||||
msgid ""
|
||||
"If set to Sale Order, keep native Odoo behaviour for creation of invoices from Sale Orders.\n"
|
||||
"If set to Stock Picking, disallow creation of Invoices from Sale Orders for the cases where Product Type are 'Product', in case of 'Service' still will be possible create from Sale Order."
|
||||
msgstr ""
|
||||
|
||||
#. module: sale_stock_picking_invoicing
|
||||
#: model:ir.model.fields,field_description:sale_stock_picking_invoicing.field_res_company__sale_invoicing_policy
|
||||
#: model:ir.model.fields,field_description:sale_stock_picking_invoicing.field_res_config_settings__sale_invoicing_policy
|
||||
msgid "Sale Invoicing Policy"
|
||||
msgstr ""
|
||||
|
||||
#. module: sale_stock_picking_invoicing
|
||||
#: model:ir.model.fields.selection,name:sale_stock_picking_invoicing.selection__res_company__sale_invoicing_policy__sale_order
|
||||
msgid "Sale Order"
|
||||
msgstr ""
|
||||
|
||||
#. module: sale_stock_picking_invoicing
|
||||
#: model:ir.model,name:sale_stock_picking_invoicing.model_sale_order
|
||||
msgid "Sales Order"
|
||||
msgstr ""
|
||||
|
||||
#. module: sale_stock_picking_invoicing
|
||||
#: model:ir.model,name:sale_stock_picking_invoicing.model_sale_order_line
|
||||
msgid "Sales Order Line"
|
||||
msgstr ""
|
||||
|
||||
#. module: sale_stock_picking_invoicing
|
||||
#: model:ir.model,name:sale_stock_picking_invoicing.model_stock_invoice_onshipping
|
||||
msgid "Stock Invoice Onshipping"
|
||||
msgstr ""
|
||||
|
||||
#. module: sale_stock_picking_invoicing
|
||||
#: model:ir.model,name:sale_stock_picking_invoicing.model_stock_move
|
||||
msgid "Stock Move"
|
||||
msgstr ""
|
||||
|
||||
#. module: sale_stock_picking_invoicing
|
||||
#: model:ir.model.fields.selection,name:sale_stock_picking_invoicing.selection__res_company__sale_invoicing_policy__stock_picking
|
||||
msgid "Stock Picking"
|
||||
msgstr ""
|
||||
|
||||
#. module: sale_stock_picking_invoicing
|
||||
#: model_terms:ir.ui.view,arch_db:sale_stock_picking_invoicing.sale_stock_picking_invoicing_res_config_settings_form
|
||||
msgid "This default value is applied to creation of Invoice."
|
||||
msgstr ""
|
||||
|
||||
#. module: sale_stock_picking_invoicing
|
||||
#: model:ir.model,name:sale_stock_picking_invoicing.model_stock_picking
|
||||
msgid "Transfer"
|
||||
msgstr ""
|
||||
|
||||
#. module: sale_stock_picking_invoicing
|
||||
#. odoo-python
|
||||
#: code:addons/sale_stock_picking_invoicing/models/sale_order.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"When 'Sale Invoicing Policy' is defined as'Stock Picking' the Invoice can "
|
||||
"only be created from the Stock Picking, if necessary you can change in the "
|
||||
"Company or Sale Settings."
|
||||
msgstr ""
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
from . import sale_order_line
|
||||
from . import stock_move
|
||||
from . import sale_order
|
||||
from . import stock_picking
|
||||
from . import res_company
|
||||
from . import res_config_settings
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
# Copyright (C) 2021-TODAY Akretion
|
||||
# @author Magno Costa <magno.costa@akretion.com.br>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import api, fields, models
|
||||
|
||||
|
||||
class ResCompany(models.Model):
|
||||
_inherit = "res.company"
|
||||
|
||||
@api.model
|
||||
def _default_sale_invoicing_policy(self):
|
||||
# In order to avoid errors in the CI tests environment when Created
|
||||
# Invoice from Sale Order using sale.advance.payment.inv object
|
||||
# is necessary let default policy as sale_order
|
||||
# TODO: Is there other form to avoid this problem?
|
||||
result = "stock_picking"
|
||||
module_base = self.env["ir.module.module"].search([("name", "=", "base")])
|
||||
if module_base.demo:
|
||||
result = "sale_order"
|
||||
return result
|
||||
|
||||
sale_invoicing_policy = fields.Selection(
|
||||
selection=[
|
||||
("sale_order", "Sale Order"),
|
||||
("stock_picking", "Stock Picking"),
|
||||
],
|
||||
help="If set to Sale Order, keep native Odoo behaviour for creation of"
|
||||
" invoices from Sale Orders.\n"
|
||||
"If set to Stock Picking, disallow creation of Invoices from Sale Orders"
|
||||
" for the cases where Product Type are 'Product', in case of 'Service'"
|
||||
" still will be possible create from Sale Order.",
|
||||
default=_default_sale_invoicing_policy,
|
||||
)
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
# Copyright (C) 2021-TODAY Akretion
|
||||
# @author Magno Costa <magno.costa@akretion.com.br>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class ResConfigSettings(models.TransientModel):
|
||||
_inherit = "res.config.settings"
|
||||
|
||||
sale_invoicing_policy = fields.Selection(
|
||||
related="company_id.sale_invoicing_policy", readonly=False
|
||||
)
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
# Copyright (C) 2020-TODAY Akretion
|
||||
# @author Magno Costa <magno.costa@akretion.com.br>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import _, models
|
||||
from odoo.exceptions import UserError
|
||||
|
||||
|
||||
class SaleOrder(models.Model):
|
||||
_inherit = "sale.order"
|
||||
|
||||
def _get_invoiceable_lines(self, final=False):
|
||||
"""Return the invoiceable lines for order `self`."""
|
||||
lines = super()._get_invoiceable_lines(final)
|
||||
model = self.env.context.get("active_model")
|
||||
if (
|
||||
self.company_id.sale_invoicing_policy == "stock_picking"
|
||||
and model != "stock.picking"
|
||||
):
|
||||
new_lines = lines.filtered(
|
||||
lambda ln: ln.product_id.type != "product" and not ln.is_downpayment
|
||||
)
|
||||
if new_lines:
|
||||
# Case lines with Product Type 'service'
|
||||
lines = new_lines
|
||||
else:
|
||||
# Case only Products Type 'product'
|
||||
raise UserError(
|
||||
_(
|
||||
"When 'Sale Invoicing Policy' is defined as"
|
||||
"'Stock Picking' the Invoice can only be created"
|
||||
" from the Stock Picking, if necessary you can change"
|
||||
" in the Company or Sale Settings."
|
||||
)
|
||||
)
|
||||
|
||||
return lines
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
# Copyright (C) 2013-Today - Akretion (<http://www.akretion.com>).
|
||||
# @author Renato Lima <renato.lima@akretion.com.br>
|
||||
# @author Raphael Valyi <raphael.valyi@akretion.com>
|
||||
# @author Magno Costa <magno.costa@akretion.com.br>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import models
|
||||
|
||||
|
||||
class SaleOrderLine(models.Model):
|
||||
_inherit = "sale.order.line"
|
||||
|
||||
def _prepare_procurement_values(self, group_id=False):
|
||||
values = super()._prepare_procurement_values(group_id)
|
||||
if self.order_id.company_id.sale_invoicing_policy == "stock_picking":
|
||||
values["invoice_state"] = "2binvoiced"
|
||||
|
||||
return values
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
# Copyright (C) 2020-TODAY KMEE
|
||||
# @author Gabriel Cardoso de Faria <gabriel.cardoso@kmee.com.br>
|
||||
# Copyright (C) 2021-TODAY Akretion
|
||||
# @author Magno Costa <magno.costa@akretion.com.br>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class StockMove(models.Model):
|
||||
_inherit = "stock.move"
|
||||
|
||||
def _get_price_unit_invoice(self, inv_type, partner, qty=1):
|
||||
result = super()._get_price_unit_invoice(inv_type, partner, qty)
|
||||
move = fields.first(self)
|
||||
if move.sale_line_id and move.sale_line_id.price_unit != result:
|
||||
result = move.sale_line_id.price_unit
|
||||
|
||||
return result
|
||||
|
||||
def _get_new_picking_values(self):
|
||||
values = super()._get_new_picking_values()
|
||||
move = fields.first(self)
|
||||
if move.sale_line_id:
|
||||
company = move.sale_line_id.order_id.company_id
|
||||
if company.sale_invoicing_policy == "stock_picking":
|
||||
values["invoice_state"] = "2binvoiced"
|
||||
|
||||
return values
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
# Copyright (C) 2021-TODAY Akretion
|
||||
# @author Magno Costa <magno.costa@akretion.com.br>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import models
|
||||
|
||||
|
||||
class StockPicking(models.Model):
|
||||
_inherit = "stock.picking"
|
||||
|
||||
def _get_partner_to_invoice(self):
|
||||
partner_id = super()._get_partner_to_invoice()
|
||||
if self.sale_id:
|
||||
partner_id = self.sale_id.partner_invoice_id.id
|
||||
|
||||
return partner_id
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
Define 'Sale Invoicing Policy', if the invoice should be created from Sale Order or from Stock Picking, go to:
|
||||
|
||||
**Settings > Users & Companies > Companies**
|
||||
|
||||
or
|
||||
|
||||
**Sales > Configuration > Settings in Invoicing**
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
* `Akretion <https://akretion.com>`_:
|
||||
|
||||
* Renato Lima <renato.lima@akretion.com.br>
|
||||
* Raphaël Valyi <raphael.valyi@akretion.com.br>
|
||||
* Magno Costa <magno.costa@akretion.com.br>
|
||||
|
||||
* `KMEE <https://www.kmee.com.br>`_:
|
||||
|
||||
* Gabriel Cardoso de Faria <gabriel.cardoso@kmee.com.br>
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
The development of this module has been financially supported by:
|
||||
|
||||
* Aketion - www.akretion.com
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
This module extends Stock Picking Invoicing implementation to Sale, you can define the 'Sale Invoicing Policy':
|
||||
|
||||
* If set to Sale Order, keep native Odoo behaviour for creation of invoices from Sale Orders.
|
||||
|
||||
* If set to Stock Picking, disallow creation of Invoices from Sale Orders for the cases where the Product Type are 'Product', in case of 'Service' still will be possible create from Sale Order.
|
||||
|
||||
For stock.moves, override price calculation that is present in stock_picking_invoicing, with the native Sale Order Line price calculation, same for the partner_id and other informations used to create the Invoice from Sale Order as such Payment Terms, Down Payments, Incoterm, Client Ref,etc by using sale methods to get data in order to avoid the necessity of 'glue modules' (small modules made just to avoid indirect dependencies), so in the case of any module include a new field in Invoice created by Sale this field also be include when created by Picking, for example the modules `Account Payment Sale`_ and `Sale Commission`_.
|
||||
|
||||
.. _`Account Payment Sale`: https://github.com/OCA/bank-payment/tree/14.0/account_payment_sale
|
||||
.. _`Sale Commission`: https://github.com/OCA/commission/tree/14.0/sale_commission
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
16.0.1.0.0 (2025-01-14)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* Migration to version 16.0
|
||||
|
||||
15.0.1.0.0 (2024-10-25)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* Migration to version 15.0 .
|
||||
|
||||
14.0.1.0.0 (2024-03-12)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* [ADD] Module sale_stock_picking_invoicing based in l10n_br_sale_stock https://github.com/OCA/l10n-brazil/tree/14.0/l10n_br_sale_stock .
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
This module depends on:
|
||||
|
||||
* sale_management
|
||||
* sale_stock
|
||||
* stock_picking_invoicing
|
||||
* stock_picking_invoice_link
|
||||
|
|
@ -0,0 +1 @@
|
|||
* It is be possible reference multiple sale lines in only one invoice line, but there are a problem the field qty_invoiced in sale.order.line show the quantity of invoice line without consider, in this case, that the value is the sum of others sale lines https://github.com/odoo/odoo/blob/14.0/addons/sale/models/sale.py#L1230, what can make confuse the user about the real Invoiced Quantity, reference https://github.com/odoo/odoo/pull/77195
|
||||
|
|
@ -0,0 +1 @@
|
|||
If 'Stock Picking' is choose as Policy the creation of Invoice from Sale Order works only for Service lines, in the case of Sale Order has Products and Service lines will be create two Invoices.
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 9.2 KiB |
|
|
@ -0,0 +1,505 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="generator" content="Docutils: https://docutils.sourceforge.io/" />
|
||||
<title>Sales Stock Picking Invocing</title>
|
||||
<style type="text/css">
|
||||
|
||||
/*
|
||||
:Author: David Goodger (goodger@python.org)
|
||||
:Id: $Id: html4css1.css 9511 2024-01-13 09:50:07Z milde $
|
||||
:Copyright: This stylesheet has been placed in the public domain.
|
||||
|
||||
Default cascading style sheet for the HTML output of Docutils.
|
||||
Despite the name, some widely supported CSS2 features are used.
|
||||
|
||||
See https://docutils.sourceforge.io/docs/howto/html-stylesheets.html for how to
|
||||
customize this style sheet.
|
||||
*/
|
||||
|
||||
/* used to remove borders from tables and images */
|
||||
.borderless, table.borderless td, table.borderless th {
|
||||
border: 0 }
|
||||
|
||||
table.borderless td, table.borderless th {
|
||||
/* Override padding for "table.docutils td" with "! important".
|
||||
The right padding separates the table cells. */
|
||||
padding: 0 0.5em 0 0 ! important }
|
||||
|
||||
.first {
|
||||
/* Override more specific margin styles with "! important". */
|
||||
margin-top: 0 ! important }
|
||||
|
||||
.last, .with-subtitle {
|
||||
margin-bottom: 0 ! important }
|
||||
|
||||
.hidden {
|
||||
display: none }
|
||||
|
||||
.subscript {
|
||||
vertical-align: sub;
|
||||
font-size: smaller }
|
||||
|
||||
.superscript {
|
||||
vertical-align: super;
|
||||
font-size: smaller }
|
||||
|
||||
a.toc-backref {
|
||||
text-decoration: none ;
|
||||
color: black }
|
||||
|
||||
blockquote.epigraph {
|
||||
margin: 2em 5em ; }
|
||||
|
||||
dl.docutils dd {
|
||||
margin-bottom: 0.5em }
|
||||
|
||||
object[type="image/svg+xml"], object[type="application/x-shockwave-flash"] {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* Uncomment (and remove this text!) to get bold-faced definition list terms
|
||||
dl.docutils dt {
|
||||
font-weight: bold }
|
||||
*/
|
||||
|
||||
div.abstract {
|
||||
margin: 2em 5em }
|
||||
|
||||
div.abstract p.topic-title {
|
||||
font-weight: bold ;
|
||||
text-align: center }
|
||||
|
||||
div.admonition, div.attention, div.caution, div.danger, div.error,
|
||||
div.hint, div.important, div.note, div.tip, div.warning {
|
||||
margin: 2em ;
|
||||
border: medium outset ;
|
||||
padding: 1em }
|
||||
|
||||
div.admonition p.admonition-title, div.hint p.admonition-title,
|
||||
div.important p.admonition-title, div.note p.admonition-title,
|
||||
div.tip p.admonition-title {
|
||||
font-weight: bold ;
|
||||
font-family: sans-serif }
|
||||
|
||||
div.attention p.admonition-title, div.caution p.admonition-title,
|
||||
div.danger p.admonition-title, div.error p.admonition-title,
|
||||
div.warning p.admonition-title, .code .error {
|
||||
color: red ;
|
||||
font-weight: bold ;
|
||||
font-family: sans-serif }
|
||||
|
||||
/* Uncomment (and remove this text!) to get reduced vertical space in
|
||||
compound paragraphs.
|
||||
div.compound .compound-first, div.compound .compound-middle {
|
||||
margin-bottom: 0.5em }
|
||||
|
||||
div.compound .compound-last, div.compound .compound-middle {
|
||||
margin-top: 0.5em }
|
||||
*/
|
||||
|
||||
div.dedication {
|
||||
margin: 2em 5em ;
|
||||
text-align: center ;
|
||||
font-style: italic }
|
||||
|
||||
div.dedication p.topic-title {
|
||||
font-weight: bold ;
|
||||
font-style: normal }
|
||||
|
||||
div.figure {
|
||||
margin-left: 2em ;
|
||||
margin-right: 2em }
|
||||
|
||||
div.footer, div.header {
|
||||
clear: both;
|
||||
font-size: smaller }
|
||||
|
||||
div.line-block {
|
||||
display: block ;
|
||||
margin-top: 1em ;
|
||||
margin-bottom: 1em }
|
||||
|
||||
div.line-block div.line-block {
|
||||
margin-top: 0 ;
|
||||
margin-bottom: 0 ;
|
||||
margin-left: 1.5em }
|
||||
|
||||
div.sidebar {
|
||||
margin: 0 0 0.5em 1em ;
|
||||
border: medium outset ;
|
||||
padding: 1em ;
|
||||
background-color: #ffffee ;
|
||||
width: 40% ;
|
||||
float: right ;
|
||||
clear: right }
|
||||
|
||||
div.sidebar p.rubric {
|
||||
font-family: sans-serif ;
|
||||
font-size: medium }
|
||||
|
||||
div.system-messages {
|
||||
margin: 5em }
|
||||
|
||||
div.system-messages h1 {
|
||||
color: red }
|
||||
|
||||
div.system-message {
|
||||
border: medium outset ;
|
||||
padding: 1em }
|
||||
|
||||
div.system-message p.system-message-title {
|
||||
color: red ;
|
||||
font-weight: bold }
|
||||
|
||||
div.topic {
|
||||
margin: 2em }
|
||||
|
||||
h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
|
||||
h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
|
||||
margin-top: 0.4em }
|
||||
|
||||
h1.title {
|
||||
text-align: center }
|
||||
|
||||
h2.subtitle {
|
||||
text-align: center }
|
||||
|
||||
hr.docutils {
|
||||
width: 75% }
|
||||
|
||||
img.align-left, .figure.align-left, object.align-left, table.align-left {
|
||||
clear: left ;
|
||||
float: left ;
|
||||
margin-right: 1em }
|
||||
|
||||
img.align-right, .figure.align-right, object.align-right, table.align-right {
|
||||
clear: right ;
|
||||
float: right ;
|
||||
margin-left: 1em }
|
||||
|
||||
img.align-center, .figure.align-center, object.align-center {
|
||||
display: block;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
table.align-center {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.align-left {
|
||||
text-align: left }
|
||||
|
||||
.align-center {
|
||||
clear: both ;
|
||||
text-align: center }
|
||||
|
||||
.align-right {
|
||||
text-align: right }
|
||||
|
||||
/* reset inner alignment in figures */
|
||||
div.align-right {
|
||||
text-align: inherit }
|
||||
|
||||
/* div.align-center * { */
|
||||
/* text-align: left } */
|
||||
|
||||
.align-top {
|
||||
vertical-align: top }
|
||||
|
||||
.align-middle {
|
||||
vertical-align: middle }
|
||||
|
||||
.align-bottom {
|
||||
vertical-align: bottom }
|
||||
|
||||
ol.simple, ul.simple {
|
||||
margin-bottom: 1em }
|
||||
|
||||
ol.arabic {
|
||||
list-style: decimal }
|
||||
|
||||
ol.loweralpha {
|
||||
list-style: lower-alpha }
|
||||
|
||||
ol.upperalpha {
|
||||
list-style: upper-alpha }
|
||||
|
||||
ol.lowerroman {
|
||||
list-style: lower-roman }
|
||||
|
||||
ol.upperroman {
|
||||
list-style: upper-roman }
|
||||
|
||||
p.attribution {
|
||||
text-align: right ;
|
||||
margin-left: 50% }
|
||||
|
||||
p.caption {
|
||||
font-style: italic }
|
||||
|
||||
p.credits {
|
||||
font-style: italic ;
|
||||
font-size: smaller }
|
||||
|
||||
p.label {
|
||||
white-space: nowrap }
|
||||
|
||||
p.rubric {
|
||||
font-weight: bold ;
|
||||
font-size: larger ;
|
||||
color: maroon ;
|
||||
text-align: center }
|
||||
|
||||
p.sidebar-title {
|
||||
font-family: sans-serif ;
|
||||
font-weight: bold ;
|
||||
font-size: larger }
|
||||
|
||||
p.sidebar-subtitle {
|
||||
font-family: sans-serif ;
|
||||
font-weight: bold }
|
||||
|
||||
p.topic-title {
|
||||
font-weight: bold }
|
||||
|
||||
pre.address {
|
||||
margin-bottom: 0 ;
|
||||
margin-top: 0 ;
|
||||
font: inherit }
|
||||
|
||||
pre.literal-block, pre.doctest-block, pre.math, pre.code {
|
||||
margin-left: 2em ;
|
||||
margin-right: 2em }
|
||||
|
||||
pre.code .ln { color: gray; } /* line numbers */
|
||||
pre.code, code { background-color: #eeeeee }
|
||||
pre.code .comment, code .comment { color: #5C6576 }
|
||||
pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold }
|
||||
pre.code .literal.string, code .literal.string { color: #0C5404 }
|
||||
pre.code .name.builtin, code .name.builtin { color: #352B84 }
|
||||
pre.code .deleted, code .deleted { background-color: #DEB0A1}
|
||||
pre.code .inserted, code .inserted { background-color: #A3D289}
|
||||
|
||||
span.classifier {
|
||||
font-family: sans-serif ;
|
||||
font-style: oblique }
|
||||
|
||||
span.classifier-delimiter {
|
||||
font-family: sans-serif ;
|
||||
font-weight: bold }
|
||||
|
||||
span.interpreted {
|
||||
font-family: sans-serif }
|
||||
|
||||
span.option {
|
||||
white-space: nowrap }
|
||||
|
||||
span.pre {
|
||||
white-space: pre }
|
||||
|
||||
span.problematic, pre.problematic {
|
||||
color: red }
|
||||
|
||||
span.section-subtitle {
|
||||
/* font-size relative to parent (h1..h6 element) */
|
||||
font-size: 80% }
|
||||
|
||||
table.citation {
|
||||
border-left: solid 1px gray;
|
||||
margin-left: 1px }
|
||||
|
||||
table.docinfo {
|
||||
margin: 2em 4em }
|
||||
|
||||
table.docutils {
|
||||
margin-top: 0.5em ;
|
||||
margin-bottom: 0.5em }
|
||||
|
||||
table.footnote {
|
||||
border-left: solid 1px black;
|
||||
margin-left: 1px }
|
||||
|
||||
table.docutils td, table.docutils th,
|
||||
table.docinfo td, table.docinfo th {
|
||||
padding-left: 0.5em ;
|
||||
padding-right: 0.5em ;
|
||||
vertical-align: top }
|
||||
|
||||
table.docutils th.field-name, table.docinfo th.docinfo-name {
|
||||
font-weight: bold ;
|
||||
text-align: left ;
|
||||
white-space: nowrap ;
|
||||
padding-left: 0 }
|
||||
|
||||
/* "booktabs" style (no vertical lines) */
|
||||
table.docutils.booktabs {
|
||||
border: 0px;
|
||||
border-top: 2px solid;
|
||||
border-bottom: 2px solid;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
table.docutils.booktabs * {
|
||||
border: 0px;
|
||||
}
|
||||
table.docutils.booktabs th {
|
||||
border-bottom: thin solid;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
|
||||
h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
|
||||
font-size: 100% }
|
||||
|
||||
ul.auto-toc {
|
||||
list-style-type: none }
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="document" id="sales-stock-picking-invocing">
|
||||
<h1 class="title">Sales Stock Picking Invocing</h1>
|
||||
|
||||
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
!! This file is generated by oca-gen-addon-readme !!
|
||||
!! changes will be overwritten. !!
|
||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
!! source digest: sha256:2c14793fdb5a5bca2858a4db80020eff35109d87c35e92cfc63098e219719eaf
|
||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
|
||||
<p><a class="reference external image-reference" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external image-reference" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/licence-AGPL--3-blue.png" /></a> <a class="reference external image-reference" href="https://github.com/OCA/account-invoicing/tree/16.0/sale_stock_picking_invoicing"><img alt="OCA/account-invoicing" src="https://img.shields.io/badge/github-OCA%2Faccount--invoicing-lightgray.png?logo=github" /></a> <a class="reference external image-reference" href="https://translation.odoo-community.org/projects/account-invoicing-16-0/account-invoicing-16-0-sale_stock_picking_invoicing"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external image-reference" href="https://runboat.odoo-community.org/builds?repo=OCA/account-invoicing&target_branch=16.0"><img alt="Try me on Runboat" src="https://img.shields.io/badge/runboat-Try%20me-875A7B.png" /></a></p>
|
||||
<p>This module extends Stock Picking Invoicing implementation to Sale, you can define the ‘Sale Invoicing Policy’:</p>
|
||||
<ul class="simple">
|
||||
<li>If set to Sale Order, keep native Odoo behaviour for creation of invoices from Sale Orders.</li>
|
||||
<li>If set to Stock Picking, disallow creation of Invoices from Sale Orders for the cases where the Product Type are ‘Product’, in case of ‘Service’ still will be possible create from Sale Order.</li>
|
||||
</ul>
|
||||
<p>For stock.moves, override price calculation that is present in stock_picking_invoicing, with the native Sale Order Line price calculation, same for the partner_id and other informations used to create the Invoice from Sale Order as such Payment Terms, Down Payments, Incoterm, Client Ref,etc by using sale methods to get data in order to avoid the necessity of ‘glue modules’ (small modules made just to avoid indirect dependencies), so in the case of any module include a new field in Invoice created by Sale this field also be include when created by Picking, for example the modules <a class="reference external" href="https://github.com/OCA/bank-payment/tree/14.0/account_payment_sale">Account Payment Sale</a> and <a class="reference external" href="https://github.com/OCA/commission/tree/14.0/sale_commission">Sale Commission</a>.</p>
|
||||
<p><strong>Table of contents</strong></p>
|
||||
<div class="contents local topic" id="contents">
|
||||
<ul class="simple">
|
||||
<li><a class="reference internal" href="#installation" id="toc-entry-1">Installation</a></li>
|
||||
<li><a class="reference internal" href="#configuration" id="toc-entry-2">Configuration</a></li>
|
||||
<li><a class="reference internal" href="#usage" id="toc-entry-3">Usage</a></li>
|
||||
<li><a class="reference internal" href="#known-issues-roadmap" id="toc-entry-4">Known issues / Roadmap</a></li>
|
||||
<li><a class="reference internal" href="#changelog" id="toc-entry-5">Changelog</a><ul>
|
||||
<li><a class="reference internal" href="#section-1" id="toc-entry-6">16.0.1.0.0 (2025-01-14)</a></li>
|
||||
<li><a class="reference internal" href="#section-2" id="toc-entry-7">15.0.1.0.0 (2024-10-25)</a></li>
|
||||
<li><a class="reference internal" href="#section-3" id="toc-entry-8">14.0.1.0.0 (2024-03-12)</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#bug-tracker" id="toc-entry-9">Bug Tracker</a></li>
|
||||
<li><a class="reference internal" href="#credits" id="toc-entry-10">Credits</a><ul>
|
||||
<li><a class="reference internal" href="#authors" id="toc-entry-11">Authors</a></li>
|
||||
<li><a class="reference internal" href="#contributors" id="toc-entry-12">Contributors</a></li>
|
||||
<li><a class="reference internal" href="#other-credits" id="toc-entry-13">Other credits</a></li>
|
||||
<li><a class="reference internal" href="#maintainers" id="toc-entry-14">Maintainers</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section" id="installation">
|
||||
<h1><a class="toc-backref" href="#toc-entry-1">Installation</a></h1>
|
||||
<p>This module depends on:</p>
|
||||
<ul class="simple">
|
||||
<li>sale_management</li>
|
||||
<li>sale_stock</li>
|
||||
<li>stock_picking_invoicing</li>
|
||||
<li>stock_picking_invoice_link</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section" id="configuration">
|
||||
<h1><a class="toc-backref" href="#toc-entry-2">Configuration</a></h1>
|
||||
<p>Define ‘Sale Invoicing Policy’, if the invoice should be created from Sale Order or from Stock Picking, go to:</p>
|
||||
<p><strong>Settings > Users & Companies > Companies</strong></p>
|
||||
<p>or</p>
|
||||
<p><strong>Sales > Configuration > Settings in Invoicing</strong></p>
|
||||
</div>
|
||||
<div class="section" id="usage">
|
||||
<h1><a class="toc-backref" href="#toc-entry-3">Usage</a></h1>
|
||||
<p>If ‘Stock Picking’ is choose as Policy the creation of Invoice from Sale Order works only for Service lines, in the case of Sale Order has Products and Service lines will be create two Invoices.</p>
|
||||
</div>
|
||||
<div class="section" id="known-issues-roadmap">
|
||||
<h1><a class="toc-backref" href="#toc-entry-4">Known issues / Roadmap</a></h1>
|
||||
<ul class="simple">
|
||||
<li>It is be possible reference multiple sale lines in only one invoice line, but there are a problem the field qty_invoiced in sale.order.line show the quantity of invoice line without consider, in this case, that the value is the sum of others sale lines <a class="reference external" href="https://github.com/odoo/odoo/blob/14.0/addons/sale/models/sale.py#L1230">https://github.com/odoo/odoo/blob/14.0/addons/sale/models/sale.py#L1230</a>, what can make confuse the user about the real Invoiced Quantity, reference <a class="reference external" href="https://github.com/odoo/odoo/pull/77195">https://github.com/odoo/odoo/pull/77195</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section" id="changelog">
|
||||
<h1><a class="toc-backref" href="#toc-entry-5">Changelog</a></h1>
|
||||
<div class="section" id="section-1">
|
||||
<h2><a class="toc-backref" href="#toc-entry-6">16.0.1.0.0 (2025-01-14)</a></h2>
|
||||
<ul class="simple">
|
||||
<li>Migration to version 16.0</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section" id="section-2">
|
||||
<h2><a class="toc-backref" href="#toc-entry-7">15.0.1.0.0 (2024-10-25)</a></h2>
|
||||
<ul class="simple">
|
||||
<li>Migration to version 15.0 .</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section" id="section-3">
|
||||
<h2><a class="toc-backref" href="#toc-entry-8">14.0.1.0.0 (2024-03-12)</a></h2>
|
||||
<ul class="simple">
|
||||
<li>[ADD] Module sale_stock_picking_invoicing based in l10n_br_sale_stock <a class="reference external" href="https://github.com/OCA/l10n-brazil/tree/14.0/l10n_br_sale_stock">https://github.com/OCA/l10n-brazil/tree/14.0/l10n_br_sale_stock</a> .</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="bug-tracker">
|
||||
<h1><a class="toc-backref" href="#toc-entry-9">Bug Tracker</a></h1>
|
||||
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/account-invoicing/issues">GitHub Issues</a>.
|
||||
In case of trouble, please check there if your issue has already been reported.
|
||||
If you spotted it first, help us to smash it by providing a detailed and welcomed
|
||||
<a class="reference external" href="https://github.com/OCA/account-invoicing/issues/new?body=module:%20sale_stock_picking_invoicing%0Aversion:%2016.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
|
||||
<p>Do not contact contributors directly about support or help with technical issues.</p>
|
||||
</div>
|
||||
<div class="section" id="credits">
|
||||
<h1><a class="toc-backref" href="#toc-entry-10">Credits</a></h1>
|
||||
<div class="section" id="authors">
|
||||
<h2><a class="toc-backref" href="#toc-entry-11">Authors</a></h2>
|
||||
<ul class="simple">
|
||||
<li>Akretion</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section" id="contributors">
|
||||
<h2><a class="toc-backref" href="#toc-entry-12">Contributors</a></h2>
|
||||
<ul class="simple">
|
||||
<li><a class="reference external" href="https://akretion.com">Akretion</a>:<ul>
|
||||
<li>Renato Lima <<a class="reference external" href="mailto:renato.lima@akretion.com.br">renato.lima@akretion.com.br</a>></li>
|
||||
<li>Raphaël Valyi <<a class="reference external" href="mailto:raphael.valyi@akretion.com.br">raphael.valyi@akretion.com.br</a>></li>
|
||||
<li>Magno Costa <<a class="reference external" href="mailto:magno.costa@akretion.com.br">magno.costa@akretion.com.br</a>></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference external" href="https://www.kmee.com.br">KMEE</a>:<ul>
|
||||
<li>Gabriel Cardoso de Faria <<a class="reference external" href="mailto:gabriel.cardoso@kmee.com.br">gabriel.cardoso@kmee.com.br</a>></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section" id="other-credits">
|
||||
<h2><a class="toc-backref" href="#toc-entry-13">Other credits</a></h2>
|
||||
<p>The development of this module has been financially supported by:</p>
|
||||
<ul class="simple">
|
||||
<li>Aketion - www.akretion.com</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section" id="maintainers">
|
||||
<h2><a class="toc-backref" href="#toc-entry-14">Maintainers</a></h2>
|
||||
<p>This module is maintained by the OCA.</p>
|
||||
<a class="reference external image-reference" href="https://odoo-community.org">
|
||||
<img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" />
|
||||
</a>
|
||||
<p>OCA, or the Odoo Community Association, is a nonprofit organization whose
|
||||
mission is to support the collaborative development of Odoo features and
|
||||
promote its widespread use.</p>
|
||||
<p>Current <a class="reference external" href="https://odoo-community.org/page/maintainer-role">maintainers</a>:</p>
|
||||
<p><a class="reference external image-reference" href="https://github.com/mbcosta"><img alt="mbcosta" src="https://github.com/mbcosta.png?size=40px" /></a> <a class="reference external image-reference" href="https://github.com/renatonlima"><img alt="renatonlima" src="https://github.com/renatonlima.png?size=40px" /></a></p>
|
||||
<p>This module is part of the <a class="reference external" href="https://github.com/OCA/account-invoicing/tree/16.0/sale_stock_picking_invoicing">OCA/account-invoicing</a> project on GitHub.</p>
|
||||
<p>You are welcome to contribute. To learn how please visit <a class="reference external" href="https://odoo-community.org/page/Contribute">https://odoo-community.org/page/Contribute</a>.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1 @@
|
|||
from . import test_sale_stock
|
||||
|
|
@ -0,0 +1,435 @@
|
|||
# Copyright (C) 2021-TODAY Akretion
|
||||
# @author Magno Costa <magno.costa@akretion.com.br>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import exceptions
|
||||
from odoo.tests import Form
|
||||
|
||||
from odoo.addons.stock_picking_invoicing.tests.common import TestPickingInvoicingCommon
|
||||
|
||||
|
||||
class TestSaleStock(TestPickingInvoicingCommon):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
cls.account_move_model = cls.env["account.move"]
|
||||
cls.invoice_wizard = cls.env["stock.invoice.onshipping"]
|
||||
cls.stock_return_picking = cls.env["stock.return.picking"]
|
||||
cls.stock_picking = cls.env["stock.picking"]
|
||||
# In order to avoid errors in the tests CI environment when the tests
|
||||
# Create of Invoice by Sale Order using sale.advance.payment.inv object
|
||||
# is necessary let default policy as sale_order, just affect demo data.
|
||||
# TODO: Is there other form to avoid this problem?
|
||||
cls.companies = cls.env["res.company"].search(
|
||||
[("sale_invoicing_policy", "=", "sale_order")]
|
||||
)
|
||||
for company in cls.companies:
|
||||
company.sale_invoicing_policy = "stock_picking"
|
||||
|
||||
def test_01_sale_stock_return(self):
|
||||
"""
|
||||
Test a SO with a product invoiced on delivery. Deliver and invoice
|
||||
the SO, then do a return of the picking. Check that a refund
|
||||
invoice is well generated.
|
||||
"""
|
||||
# intial so
|
||||
self.partner = self.env.ref(
|
||||
"sale_stock_picking_invoicing.res_partner_2_address"
|
||||
)
|
||||
self.product = self.env.ref("product.product_delivery_01")
|
||||
so_vals = {
|
||||
"partner_id": self.partner.id,
|
||||
"partner_invoice_id": self.partner.id,
|
||||
"partner_shipping_id": self.partner.id,
|
||||
"order_line": [
|
||||
(
|
||||
0,
|
||||
0,
|
||||
{
|
||||
"name": self.product.name,
|
||||
"product_id": self.product.id,
|
||||
"product_uom_qty": 3.0,
|
||||
"product_uom": self.product.uom_id.id,
|
||||
"price_unit": self.product.list_price,
|
||||
},
|
||||
)
|
||||
],
|
||||
"pricelist_id": self.env.ref("product.list0").id,
|
||||
}
|
||||
self.so = self.env["sale.order"].create(so_vals)
|
||||
|
||||
# confirm our standard so, check the picking
|
||||
self.so.action_confirm()
|
||||
self.assertTrue(
|
||||
self.so.picking_ids,
|
||||
'Sale Stock: no picking created for "invoice on '
|
||||
'delivery" storable products',
|
||||
)
|
||||
|
||||
# set stock.picking to be invoiced
|
||||
self.assertTrue(
|
||||
len(self.so.picking_ids) == 1,
|
||||
"More than one stock " "picking for sale.order",
|
||||
)
|
||||
|
||||
# Check Sale Invoicing Policy Warning to force create Invoice from Picking
|
||||
with self.assertRaises(exceptions.UserError):
|
||||
self.so._create_invoices(final=True)
|
||||
|
||||
self.so.picking_ids.set_to_be_invoiced()
|
||||
|
||||
# validate stock.picking
|
||||
stock_picking = self.so.picking_ids
|
||||
|
||||
# compare sale.order.line with stock.move
|
||||
stock_move = stock_picking.move_ids
|
||||
sale_order_line = self.so.order_line
|
||||
|
||||
sm_fields = [key for key in self.env["stock.move"]._fields.keys()]
|
||||
sol_fields = [key for key in self.env["sale.order.line"]._fields.keys()]
|
||||
|
||||
skipped_fields = [
|
||||
"id",
|
||||
# 'S00029/FURN_7777: Stock>Customers' != 'S00029 - Office Chair'
|
||||
"display_name",
|
||||
"state",
|
||||
# Price Unit in move is different from sale line
|
||||
# TODO: Should be equal? After Confirmed stock picking
|
||||
# the value will be change based Stock Valuation
|
||||
# configuration.
|
||||
"price_unit",
|
||||
# There are a diference for field Name
|
||||
# '[FURN_7777] Office Chair' != 'Office Chair'
|
||||
"name",
|
||||
]
|
||||
common_fields = list(set(sm_fields) & set(sol_fields) - set(skipped_fields))
|
||||
|
||||
for field in common_fields:
|
||||
self.assertEqual(
|
||||
stock_move[field],
|
||||
sale_order_line[field],
|
||||
"Field %s failed to transfer from "
|
||||
"sale.order.line to stock.move" % field,
|
||||
)
|
||||
|
||||
def test_picking_sale_order_product_and_service(self):
|
||||
"""
|
||||
Test Sale Order with product and service
|
||||
"""
|
||||
|
||||
sale_order_form = sale_order_form = Form(
|
||||
self.env.ref("sale_stock_picking_invoicing.main_company-sale_order_2")
|
||||
)
|
||||
# Necessary to get the currency
|
||||
sale_order_form.pricelist_id = self.env.ref("product.list0")
|
||||
sale_order_2 = sale_order_form.save()
|
||||
sale_order_2.action_confirm()
|
||||
# Method to create invoice in sale order should work only
|
||||
# for lines where products are of TYPE Service
|
||||
sale_order_2._create_invoices()
|
||||
# Should be exist one Invoice
|
||||
self.assertEqual(1, sale_order_2.invoice_count)
|
||||
for invoice in sale_order_2.invoice_ids:
|
||||
line = invoice.invoice_line_ids.filtered(
|
||||
lambda ln: ln.product_id.type == "service"
|
||||
)
|
||||
self.assertEqual(line.product_id.type, "service")
|
||||
# Invoice of Service
|
||||
invoice.action_post()
|
||||
self.assertEqual(
|
||||
invoice.state, "posted", "Invoice should be in state Posted"
|
||||
)
|
||||
|
||||
picking = sale_order_2.picking_ids
|
||||
# Only the line of Type Product
|
||||
self.assertEqual(len(picking.move_ids_without_package), 1)
|
||||
self.assertEqual(picking.invoice_state, "2binvoiced")
|
||||
self.picking_move_state(picking)
|
||||
|
||||
# Test Create Invoice from Sale when raise UseError
|
||||
context = {
|
||||
"active_model": "sale.order",
|
||||
"active_id": sale_order_2.id,
|
||||
"active_ids": sale_order_2.ids,
|
||||
}
|
||||
payment = (
|
||||
self.env["sale.advance.payment.inv"]
|
||||
.with_context(**context)
|
||||
.create(
|
||||
{
|
||||
"advance_payment_method": "delivered",
|
||||
}
|
||||
)
|
||||
)
|
||||
with self.assertRaises(exceptions.UserError):
|
||||
payment.with_context(**context).create_invoices()
|
||||
|
||||
invoice = self.create_invoice_wizard(picking)
|
||||
self.assertEqual(picking.invoice_state, "invoiced")
|
||||
self.assertIn(invoice, picking.invoice_ids)
|
||||
self.assertIn(picking, invoice.picking_ids)
|
||||
# Picking with Partner Shipping from Sale Order
|
||||
self.assertEqual(picking.partner_id, sale_order_2.partner_shipping_id)
|
||||
# Invoice created with Partner Invoice from Sale Order
|
||||
self.assertEqual(invoice.partner_id, sale_order_2.partner_invoice_id)
|
||||
# Invoice created with Partner Shipping from Picking
|
||||
self.assertEqual(invoice.partner_shipping_id, picking.partner_id)
|
||||
# When informed Payment Term in Sale Orde should be
|
||||
# used instead of the default in Partner.
|
||||
self.assertEqual(invoice.invoice_payment_term_id, sale_order_2.payment_term_id)
|
||||
|
||||
# 1 Product 1 Note should be created
|
||||
self.assertEqual(len(invoice.invoice_line_ids), 2)
|
||||
|
||||
# In the Sale Order should be exist two Invoices, one
|
||||
# for Product other for Service
|
||||
self.assertEqual(2, sale_order_2.invoice_count)
|
||||
|
||||
# Confirm Invoice
|
||||
invoice.action_post()
|
||||
self.assertEqual(invoice.state, "posted", "Invoice should be in state Posted.")
|
||||
|
||||
# Check Invoiced QTY
|
||||
for line in sale_order_2.order_line.filtered(
|
||||
lambda ln: ln.product_id.type == "product"
|
||||
):
|
||||
self.assertEqual(line.product_uom_qty, line.qty_invoiced)
|
||||
# Test the qty_to_invoice
|
||||
line.product_id.invoice_policy = "order"
|
||||
self.assertEqual(line.qty_to_invoice, 0.0)
|
||||
|
||||
# Check if the Sale Lines fields are equals to Invoice Lines
|
||||
sol_fields = [key for key in self.env["sale.order.line"]._fields.keys()]
|
||||
|
||||
acl_fields = [key for key in self.env["account.move.line"]._fields.keys()]
|
||||
|
||||
skipped_fields = [
|
||||
"id",
|
||||
"display_name",
|
||||
"state",
|
||||
"create_date",
|
||||
# By th TAX 15% automatic add in invoice the value change
|
||||
"price_total",
|
||||
# Necessary after call onchange_partner_id
|
||||
"write_date",
|
||||
"__last_update",
|
||||
# Field sequence add in creation of Invoice
|
||||
"sequence",
|
||||
# In the sale.orde.line display_type has only line_section
|
||||
# and line_note, the acccount.move.line has more options
|
||||
"display_type",
|
||||
]
|
||||
|
||||
common_fields = list(set(acl_fields) & set(sol_fields) - set(skipped_fields))
|
||||
sale_order_line = picking.move_ids_without_package.filtered(
|
||||
lambda ln: ln.sale_line_id
|
||||
).sale_line_id
|
||||
invoice_lines = picking.invoice_ids.invoice_line_ids.filtered(
|
||||
lambda ln: ln.product_id
|
||||
)
|
||||
# Necessary for get analytic_precision
|
||||
# this problem only occours in the tests, by some reason not
|
||||
# identify yet, but works in the screen the default behavior
|
||||
with Form(invoice_lines) as line:
|
||||
line.save()
|
||||
|
||||
for field in common_fields:
|
||||
self.assertEqual(
|
||||
sale_order_line[field],
|
||||
invoice_lines[field],
|
||||
"Field %s failed to transfer from "
|
||||
"sale.order.line to account.invoice.line" % field,
|
||||
)
|
||||
|
||||
# Return Picking
|
||||
picking_devolution = self.return_picking_wizard(picking)
|
||||
|
||||
self.assertEqual(picking_devolution.invoice_state, "2binvoiced")
|
||||
for line in picking_devolution.move_ids:
|
||||
self.assertEqual(line.invoice_state, "2binvoiced")
|
||||
|
||||
self.picking_move_state(picking_devolution)
|
||||
self.assertEqual(picking_devolution.state, "done", "Change state fail.")
|
||||
|
||||
invoice_devolution = self.create_invoice_wizard(picking_devolution)
|
||||
# Confirm Invoice
|
||||
invoice_devolution.action_post()
|
||||
self.assertEqual(
|
||||
invoice_devolution.state, "posted", "Invoice should be in state Posted"
|
||||
)
|
||||
# Test need to be comment because there are a problem with module
|
||||
# sale_line_refund_to_invoice_qty
|
||||
# https://github.com/OCA/account-invoicing/blob/
|
||||
# 14.0/sale_line_refund_to_invoice_qty/models/sale.py#L20
|
||||
# when the tests run in CI of the repo the test fail.
|
||||
# TODO: The module should be compatible with this case?
|
||||
# Check Invoiced QTY update after Refund
|
||||
# for line in sale_order_2.order_line:
|
||||
# # Check Product line
|
||||
# if line.product_id.type == "product":
|
||||
# # self.assertEqual(0.0, line.qty_invoiced)
|
||||
|
||||
def test_picking_invoicing_partner_shipping_invoiced(self):
|
||||
"""
|
||||
Test the invoice generation grouped by partner/product with 2
|
||||
picking and 2 moves per picking, but Partner to Shipping is
|
||||
different from Partner to Invoice.
|
||||
"""
|
||||
sale_order_1 = self.env.ref(
|
||||
"sale_stock_picking_invoicing.main_company-sale_order_1"
|
||||
)
|
||||
sale_order_1.action_confirm()
|
||||
picking = sale_order_1.picking_ids
|
||||
self.picking_move_state(picking)
|
||||
sale_order_2 = self.env.ref(
|
||||
"sale_stock_picking_invoicing.main_company-sale_order_2"
|
||||
)
|
||||
sale_order_2.action_confirm()
|
||||
picking2 = sale_order_2.picking_ids
|
||||
self.picking_move_state(picking2)
|
||||
pickings = picking | picking2
|
||||
invoice = self.create_invoice_wizard(pickings)
|
||||
# Groupping Invoice
|
||||
self.assertEqual(len(invoice), 1)
|
||||
# Invoice should be create with the partner_invoice_id
|
||||
self.assertEqual(invoice.partner_id, sale_order_1.partner_invoice_id)
|
||||
# Invoice partner shipping should be the same of picking
|
||||
self.assertEqual(invoice.partner_shipping_id, picking.partner_id)
|
||||
self.assertIn(invoice, picking.invoice_ids)
|
||||
self.assertIn(picking, invoice.picking_ids)
|
||||
self.assertIn(invoice, picking2.invoice_ids)
|
||||
self.assertIn(picking2, invoice.picking_ids)
|
||||
|
||||
# TODO: Grouping sale line with KEY should be analise
|
||||
# self.assertEqual(len(invoice.invoice_line_ids), 2)
|
||||
# 3 Products, 2 Note and 2 Section
|
||||
self.assertEqual(len(invoice.invoice_line_ids), 7)
|
||||
for inv_line in invoice.invoice_line_ids.filtered(lambda ln: ln.product_id):
|
||||
self.assertTrue(inv_line.tax_ids, "Error to map Sale Tax in invoice.line.")
|
||||
# Post the Invoice to validate the fields
|
||||
invoice.action_post()
|
||||
|
||||
def test_ungrouping_pickings_partner_shipping_different(self):
|
||||
"""
|
||||
Test the invoice generation grouped by partner/product with 3
|
||||
picking and 2 moves per picking, the 3 has the same Partner to
|
||||
Invoice but one has Partner to Shipping so shouldn't be grouping.
|
||||
"""
|
||||
|
||||
sale_order_1 = self.env.ref(
|
||||
"sale_stock_picking_invoicing.main_company-sale_order_1"
|
||||
)
|
||||
sale_order_1.action_confirm()
|
||||
picking = sale_order_1.picking_ids
|
||||
self.picking_move_state(picking)
|
||||
|
||||
sale_order_3 = self.env.ref(
|
||||
"sale_stock_picking_invoicing.main_company-sale_order_3"
|
||||
)
|
||||
sale_order_3.action_confirm()
|
||||
picking3 = sale_order_3.picking_ids
|
||||
self.picking_move_state(picking3)
|
||||
|
||||
sale_order_4 = self.env.ref(
|
||||
"sale_stock_picking_invoicing.main_company-sale_order_4"
|
||||
)
|
||||
sale_order_4.action_confirm()
|
||||
picking4 = sale_order_4.picking_ids
|
||||
self.picking_move_state(picking4)
|
||||
|
||||
pickings = picking | picking3 | picking4
|
||||
invoices = self.create_invoice_wizard(pickings)
|
||||
# Even with same Partner Invoice if the Partner Shipping
|
||||
# are different should not be Groupping
|
||||
self.assertEqual(len(invoices), 2)
|
||||
|
||||
# Invoice that has different Partner Shipping
|
||||
# should be not groupping
|
||||
invoice_pick_1 = invoices.filtered(
|
||||
lambda t: t.partner_id != t.partner_shipping_id
|
||||
)
|
||||
# Invoice should be create with partner_invoice_id
|
||||
self.assertEqual(invoice_pick_1.partner_id, sale_order_1.partner_invoice_id)
|
||||
# Invoice create with Partner Shipping used in Picking
|
||||
self.assertEqual(invoice_pick_1.partner_shipping_id, picking.partner_id)
|
||||
|
||||
# Groupping Invoice
|
||||
invoice_pick_3_4 = invoices.filtered(
|
||||
lambda t: t.partner_id == t.partner_shipping_id
|
||||
)
|
||||
self.assertIn(invoice_pick_3_4, picking3.invoice_ids)
|
||||
self.assertIn(invoice_pick_3_4, picking4.invoice_ids)
|
||||
|
||||
def test_down_payment(self):
|
||||
"""Test the case with Down Payment"""
|
||||
sale_order_1 = self.env.ref(
|
||||
"sale_stock_picking_invoicing.main_company-sale_order_1"
|
||||
)
|
||||
sale_order_1.action_confirm()
|
||||
# Create Invoice Sale
|
||||
context = {
|
||||
"active_model": "sale.order",
|
||||
"active_id": sale_order_1.id,
|
||||
"active_ids": sale_order_1.ids,
|
||||
}
|
||||
# DownPayment
|
||||
payment_wizard = (
|
||||
self.env["sale.advance.payment.inv"]
|
||||
.with_context(**context)
|
||||
.create(
|
||||
{
|
||||
"advance_payment_method": "percentage",
|
||||
"amount": 50,
|
||||
}
|
||||
)
|
||||
)
|
||||
payment_wizard.create_invoices()
|
||||
|
||||
invoice_down_payment = sale_order_1.invoice_ids[0]
|
||||
invoice_down_payment.action_post()
|
||||
payment_register = Form(
|
||||
self.env["account.payment.register"].with_context(
|
||||
active_model="account.move",
|
||||
active_ids=invoice_down_payment.ids,
|
||||
)
|
||||
)
|
||||
journal_cash = self.env["account.journal"].search(
|
||||
[
|
||||
("type", "=", "cash"),
|
||||
("company_id", "=", invoice_down_payment.company_id.id),
|
||||
],
|
||||
limit=1,
|
||||
)
|
||||
payment_register.journal_id = journal_cash
|
||||
payment_register.amount = invoice_down_payment.amount_total
|
||||
payment_register.save()._create_payments()
|
||||
|
||||
picking = sale_order_1.picking_ids
|
||||
self.picking_move_state(picking)
|
||||
invoice = self.create_invoice_wizard(picking)
|
||||
# 2 Products, 2 Down Payment, 1 Note and 1 Section
|
||||
self.assertEqual(len(invoice.invoice_line_ids), 6)
|
||||
line_section = invoice.invoice_line_ids.filtered(
|
||||
lambda line: line.display_type == "line_section"
|
||||
)
|
||||
assert line_section, "Invoice without Line Section for Down Payment."
|
||||
down_payment_line = invoice.invoice_line_ids.filtered(
|
||||
lambda line: line.sale_line_ids.is_downpayment
|
||||
)
|
||||
assert down_payment_line, "Invoice without Down Payment line."
|
||||
|
||||
def test_default_value_sale_invoicing_policy(self):
|
||||
"""Test default value for sale_invoicing_policy"""
|
||||
company = self.env["res.company"].create(
|
||||
{
|
||||
"name": "Test",
|
||||
}
|
||||
)
|
||||
self.assertEqual(company.sale_invoicing_policy, "sale_order")
|
||||
|
||||
def test_picking_invocing_without_sale_order(self):
|
||||
"""Test Picking Invoicing without Sale Order"""
|
||||
picking = self.env.ref("stock_picking_invoicing.stock_picking_invoicing_1")
|
||||
self.picking_move_state(picking)
|
||||
invoice = self.create_invoice_wizard(picking)
|
||||
self.assertEqual(len(invoice), 1)
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<!--
|
||||
Copyright 2022-TODAY Akretion (http://www.akretion.com/)
|
||||
@author: Magno Costa <magno.costa@akretion.com.br>
|
||||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
-->
|
||||
<odoo>
|
||||
|
||||
<record id="sale_stock_picking_invocing_res_company_form" model="ir.ui.view">
|
||||
<field name="name">sale_stock_picking_invocing.res.company.form</field>
|
||||
<field name="model">res.company</field>
|
||||
<field name="inherit_id" ref="base.view_company_form" />
|
||||
<field name="arch" type="xml">
|
||||
<field name="vat" position="after">
|
||||
<field name="sale_invoicing_policy" />
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<!--
|
||||
Copyright 2022-TODAY Akretion (http://www.akretion.com/)
|
||||
@author: Magno Costa <magno.costa@akretion.com.br>
|
||||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
-->
|
||||
<odoo>
|
||||
|
||||
<record
|
||||
id="sale_stock_picking_invoicing_res_config_settings_form"
|
||||
model="ir.ui.view"
|
||||
>
|
||||
<field name="name">sale_stock_picking_invoicing.res.config.settings.form</field>
|
||||
<field name="model">res.config.settings</field>
|
||||
<field name="inherit_id" ref="sale.res_config_settings_view_form" />
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//div[@id='sales_settings_invoicing_policy']" position="after">
|
||||
<div
|
||||
id="sales_settings_create_invoice_policy"
|
||||
class="col-12 col-lg-6 o_setting_box"
|
||||
title="This default value is applied to creation of Invoice."
|
||||
>
|
||||
<div class="o_setting_right_pane">
|
||||
<label for="sale_invoicing_policy" />
|
||||
<div class="text-muted">
|
||||
Define if Invoice should be created from Sale Order or from Stock Picking
|
||||
</div>
|
||||
<div class="content-group">
|
||||
<div class="mt16">
|
||||
<field
|
||||
name="sale_invoicing_policy"
|
||||
class="o_light_label"
|
||||
widget="radio"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
|
|
@ -0,0 +1 @@
|
|||
from . import stock_invoice_onshipping
|
||||
|
|
@ -0,0 +1,359 @@
|
|||
# Copyright (C) 2020-TODAY KMEE
|
||||
# Copyright (C) 2021-TODAY Akretion
|
||||
# @author Magno Costa <magno.costa@akretion.com.br>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import api, fields, models
|
||||
|
||||
|
||||
class StockInvoiceOnshipping(models.TransientModel):
|
||||
|
||||
_inherit = "stock.invoice.onshipping"
|
||||
|
||||
@api.model
|
||||
def _default_has_down_payment(self):
|
||||
pickings = self._load_pickings()
|
||||
sale_pickings = pickings.filtered(lambda pk: pk.sale_id)
|
||||
downpayment_lines = False
|
||||
if sale_pickings:
|
||||
for pick in sale_pickings:
|
||||
# order = pick.sale_id
|
||||
# sale_lines = order.mapped("order_line")
|
||||
if pick.sale_id.order_line.filtered(lambda ln: ln.is_downpayment):
|
||||
downpayment_lines = True
|
||||
|
||||
return downpayment_lines
|
||||
|
||||
deduct_down_payments = fields.Boolean("Deduct down payments", default=True)
|
||||
has_down_payments = fields.Boolean(
|
||||
"Has down payments", default=_default_has_down_payment, readonly=True
|
||||
)
|
||||
|
||||
def _get_fields_not_used_from_sale(self):
|
||||
"""Fields not used from Sale 'prepare' method"""
|
||||
# For reference, fields get from 'prepare' method
|
||||
# "ref": self.client_order_ref or ''
|
||||
# "narration": self.note,
|
||||
# "campaign_id": self.campaign_id.id,
|
||||
# "medium_id": self.medium_id.id,
|
||||
# "source_id": self.source_id.id,
|
||||
# "team_id": self.team_id.id,
|
||||
# "partner_shipping_id": self.partner_shipping_id.id,
|
||||
# "partner_bank_id": self.company_id.partner_id.bank_ids.
|
||||
# filtered(lambda bank: bank.company_id.id in
|
||||
# (self.company_id.id, False))[:1].id,
|
||||
# "invoice_payment_term_id": self.payment_term_id.id,
|
||||
# "payment_reference": self.reference,
|
||||
# "transaction_ids": [(6, 0, self.transaction_ids.ids)],
|
||||
|
||||
return {
|
||||
"move_type",
|
||||
"currency_id",
|
||||
"user_id",
|
||||
"invoice_user_id",
|
||||
"partner_id",
|
||||
"fiscal_position_id",
|
||||
"journal_id", # company comes from the journal
|
||||
"invoice_origin",
|
||||
"invoice_line_ids",
|
||||
"company_id",
|
||||
# Another fields
|
||||
"__last_update",
|
||||
"display_name",
|
||||
}
|
||||
|
||||
def _build_invoice_values_from_pickings(self, pickings):
|
||||
invoice, values = super()._build_invoice_values_from_pickings(pickings)
|
||||
|
||||
sale_pickings = pickings.filtered(lambda pk: pk.sale_id)
|
||||
# Refund case don't get values from Sale Dict
|
||||
# TODO: Should get any value?
|
||||
if sale_pickings and self._get_invoice_type() != "out_refund":
|
||||
# Case more than one Sale Order the fields below will be join
|
||||
# the others will be overwritting, as done in sale module,
|
||||
# one more field include here Note/Narration
|
||||
payment_refs = set()
|
||||
refs = set()
|
||||
# Include Narration
|
||||
narration = set()
|
||||
for pick in sale_pickings.sorted(key=lambda p: p.name):
|
||||
# Other modules can included new fields in Sale Order and include
|
||||
# this fields in the dict of creation Invoice from sale, for
|
||||
# example:
|
||||
# - account_payment_sale
|
||||
# https://github.com/OCA/bank-payment/blob/14.0/
|
||||
# account_payment_sale/models/sale_order.py#L41
|
||||
# - sale_commssion
|
||||
# https://github.com/OCA/commission/blob/14.0/
|
||||
# sale_commission/models/sale_order.py#L64
|
||||
# To avoid the necessity of a 'glue' module the method get the
|
||||
# values from _prepare_invoice but removed some fields of the
|
||||
# original method, given priority for values from
|
||||
# stock_picking_invoicing dict, for now it's seems the best to
|
||||
# way to avoid the 'glue' modules problem.
|
||||
sale_values = pick.sale_id._prepare_invoice()
|
||||
# Fields to Join
|
||||
# origins.add(sale_values["invoice_origin"])
|
||||
payment_refs.add(sale_values["payment_reference"])
|
||||
refs.add(sale_values["ref"])
|
||||
narration.add(sale_values["narration"])
|
||||
|
||||
sale_values_rm = {
|
||||
k: sale_values[k]
|
||||
for k in set(sale_values) - self._get_fields_not_used_from_sale()
|
||||
}
|
||||
|
||||
values.update(sale_values_rm)
|
||||
|
||||
# Fields to join
|
||||
if len(sale_pickings) > 1:
|
||||
values.update(
|
||||
{
|
||||
"ref": ", ".join(refs)[:2000],
|
||||
# In this case Origin get Pickings Names
|
||||
# "invoice_origin": ", ".join(origins),
|
||||
"payment_reference": len(payment_refs) == 1
|
||||
and payment_refs.pop()
|
||||
or False,
|
||||
"narration": ", ".join(narration),
|
||||
}
|
||||
)
|
||||
|
||||
return invoice, values
|
||||
|
||||
# Check the comment below
|
||||
# def _get_picking_key(self, picking):
|
||||
# key = super()._get_picking_key(picking)
|
||||
# if picking.sale_id:
|
||||
# key = key + (
|
||||
# picking.sale_id.payment_term_id,
|
||||
# picking.sale_id.fiscal_position_id,
|
||||
# picking.sale_id.commitment_date,
|
||||
# picking.sale_id.analytic_account_id,
|
||||
# picking.sale_id.pricelist_id,
|
||||
# picking.sale_id.company_id,
|
||||
# )
|
||||
# return key
|
||||
|
||||
def _get_move_key(self, move):
|
||||
key = super()._get_move_key(move)
|
||||
if move.sale_line_id:
|
||||
# TODO: Analise if Sale Lines should be grouped.
|
||||
# For now remains a problem https://github.com/odoo/odoo/pull/77195
|
||||
# with field qty_invoiced at sale.order.line, when a invoice line
|
||||
# has more than one sale line related the field show the total QTY
|
||||
# of those lines, e.g:
|
||||
# product_uom_qty | qty_invoiced
|
||||
# 2.0 | 4.0
|
||||
# key = key + (
|
||||
# move.sale_line_id.price_unit,
|
||||
# move.sale_line_id.customer_lead,
|
||||
# move.sale_line_id.currency_id,
|
||||
# move.sale_line_id.tax_id,
|
||||
# move.sale_line_id.analytic_tag_ids,
|
||||
# )
|
||||
key = key + (move.sale_line_id,)
|
||||
|
||||
return key
|
||||
|
||||
def _get_fields_not_used_from_sale_line(self):
|
||||
"""Fields not used from Sale Line 'prepare' method"""
|
||||
# Original fields from sale module
|
||||
# Fields do get
|
||||
# "sequence": self.sequence,
|
||||
# "discount": self.discount,
|
||||
# "display_type": self.display_type or 'product'
|
||||
# "is_downpayment": self.is_downpayment
|
||||
# * optional_values
|
||||
# * 'N field' included in _prepare_invoice_line method
|
||||
# by another module
|
||||
|
||||
return {
|
||||
# Fields from Move has priority
|
||||
"name",
|
||||
"product_id",
|
||||
"product_uom_id",
|
||||
"quantity",
|
||||
"price_unit",
|
||||
"tax_ids",
|
||||
# Already get
|
||||
"sale_line_ids",
|
||||
"anlytic_distribution",
|
||||
# another fields
|
||||
"__last_update",
|
||||
"display_name",
|
||||
}
|
||||
|
||||
def _get_invoice_line_values(self, moves, invoice_values, invoice):
|
||||
values = super()._get_invoice_line_values(moves, invoice_values, invoice)
|
||||
move = fields.first(moves)
|
||||
if move.sale_line_id:
|
||||
# Same make above, get fields informed in Sale Line dict
|
||||
sale_line_values = move.sale_line_id._prepare_invoice_line()
|
||||
# Vals informed in any case
|
||||
values["sale_line_ids"] = [(6, 0, moves.sale_line_id.ids)]
|
||||
values["analytic_distribution"] = sale_line_values.get(
|
||||
"analytic_distribution"
|
||||
)
|
||||
# Refund case don't get values from Sale Line Dict
|
||||
# TODO: Should get any value?
|
||||
if self._get_invoice_type() != "out_refund":
|
||||
# Same make above, get fields informed in Sale Line dict
|
||||
sale_line_values = move.sale_line_id._prepare_invoice_line()
|
||||
|
||||
sale_line_values_rm = {
|
||||
k: sale_line_values[k]
|
||||
for k in set(sale_line_values)
|
||||
- self._get_fields_not_used_from_sale_line()
|
||||
}
|
||||
values.update(sale_line_values_rm)
|
||||
|
||||
return values
|
||||
|
||||
def _get_pickings_with_sale(self, invoice_values):
|
||||
pickings = self._load_pickings()
|
||||
|
||||
# Filter Picking with Sales
|
||||
picking_in_invoice_values = self.env["stock.picking"]
|
||||
for line in invoice_values.get("invoice_line_ids"):
|
||||
if line[2]:
|
||||
if len(line[2].get("move_line_ids")[0]) == 2:
|
||||
# [(4, 233)],
|
||||
move_line_id = line[2].get("move_line_ids")[0][1]
|
||||
else:
|
||||
# [(<Command.SET: 6>, 0, [51])]
|
||||
move_line_id = line[2].get("move_line_ids")[0][2]
|
||||
|
||||
move_line = self.env["stock.move"].browse(move_line_id)
|
||||
picking_in_invoice_values |= move_line.mapped("picking_id")
|
||||
|
||||
sale_pickings = pickings.filtered(
|
||||
lambda pk: pk.sale_id
|
||||
# Check Sales Ungrouped
|
||||
and pk.id in picking_in_invoice_values.ids
|
||||
)
|
||||
|
||||
return sale_pickings
|
||||
|
||||
def _create_invoice(self, invoice_values):
|
||||
"""Override this method if you need to change any values of the
|
||||
invoice and the lines before the invoice creation
|
||||
:param invoice_values: dict with the invoice and its lines
|
||||
:return: invoice
|
||||
"""
|
||||
sale_pickings = self._get_pickings_with_sale(invoice_values)
|
||||
|
||||
# Refund case don't included Section, Note or DownPayments
|
||||
if not sale_pickings or self._get_invoice_type() == "out_refund":
|
||||
return super()._create_invoice(invoice_values)
|
||||
|
||||
# Check Other Sale Lines
|
||||
# Section, Note and Down Payments
|
||||
section_note_lines = down_payment_lines = self.env["sale.order.line"]
|
||||
# Resequencing
|
||||
invoice_item_sequence = (
|
||||
0 # Incremental sequencing to keep the lines order on the invoice.
|
||||
)
|
||||
invoice_item_seq_dict = {}
|
||||
for pick in sale_pickings.sorted(key=lambda p: p.name):
|
||||
order = pick.sale_id.with_company(pick.sale_id.company_id)
|
||||
invoiceable_lines = order._get_invoiceable_lines(final=True)
|
||||
section_note_lines |= invoiceable_lines.filtered(
|
||||
lambda ln: ln.display_type in ("line_section", "line_note")
|
||||
)
|
||||
down_payment_lines |= invoiceable_lines.filtered(
|
||||
lambda ln: ln.is_downpayment
|
||||
)
|
||||
|
||||
# Use for Resequencing
|
||||
for line in order.order_line:
|
||||
invoice_item_seq_dict[line.id] = invoice_item_sequence
|
||||
invoice_item_sequence += 1
|
||||
|
||||
# Sections and Notes
|
||||
if section_note_lines:
|
||||
section_note_vals = []
|
||||
for line in section_note_lines:
|
||||
sale_line_vals = line._prepare_invoice_line()
|
||||
# Change [(4, 59)] for [(6, 0, [59])] to avoid error
|
||||
# in method to Resequencing
|
||||
sale_line_vals["sale_line_ids"] = [
|
||||
(6, 0, [sale_line_vals.get("sale_line_ids")[0][1]])
|
||||
]
|
||||
section_note_vals.append((0, 0, sale_line_vals))
|
||||
|
||||
invoice_values["invoice_line_ids"] += section_note_vals
|
||||
|
||||
# Resequencing, necessary in the case of Grouping Sale Orders
|
||||
for line in invoice_values.get("invoice_line_ids"):
|
||||
# [(6, 0, {})]
|
||||
if line[2]:
|
||||
sale_line = line[2].get("sale_line_ids")
|
||||
if sale_line:
|
||||
# [(6, 0, [58])]
|
||||
line[2]["sequence"] = invoice_item_seq_dict.get(sale_line[0][2][0])
|
||||
|
||||
# Down Payments
|
||||
# After the Resequencing to put it in the end of Invoice
|
||||
if down_payment_lines:
|
||||
down_payment_vals = []
|
||||
down_payment_section_added = False
|
||||
for line in down_payment_lines:
|
||||
if not down_payment_section_added and line.is_downpayment:
|
||||
# Create a dedicated section for the down payments
|
||||
# (put at the end of the invoiceable_lines)
|
||||
down_payment_vals.append(
|
||||
(
|
||||
0,
|
||||
0,
|
||||
line.order_id._prepare_down_payment_section_line(
|
||||
sequence=invoice_item_sequence,
|
||||
),
|
||||
),
|
||||
)
|
||||
down_payment_section_added = True
|
||||
invoice_item_sequence += 1
|
||||
|
||||
if line.is_downpayment:
|
||||
down_payment_vals.append(
|
||||
(
|
||||
0,
|
||||
0,
|
||||
line._prepare_invoice_line(
|
||||
sequence=invoice_item_sequence,
|
||||
),
|
||||
),
|
||||
)
|
||||
invoice_item_sequence += 1
|
||||
|
||||
invoice_values["invoice_line_ids"] += down_payment_vals
|
||||
|
||||
moves = (
|
||||
self.env["account.move"]
|
||||
.sudo()
|
||||
.with_context(default_move_type="out_invoice")
|
||||
.create(invoice_values)
|
||||
)
|
||||
|
||||
# param Final: if True, refunds will be generated if necessary
|
||||
final = self.deduct_down_payments
|
||||
if final:
|
||||
moves.sudo().filtered(
|
||||
lambda m: m.amount_total < 0
|
||||
).action_switch_invoice_into_refund_credit_note()
|
||||
for move in moves:
|
||||
move.message_post_with_view(
|
||||
"mail.message_origin_link",
|
||||
# In this case the Origin are Pickings
|
||||
# values={
|
||||
# "self": move,
|
||||
# "origin": move.line_ids.mapped("sale_line_ids.order_id"),
|
||||
# },
|
||||
values={
|
||||
"self": move.picking_ids,
|
||||
"origin": move.picking_ids,
|
||||
},
|
||||
subtype_id=self.env.ref("mail.mt_note").id,
|
||||
)
|
||||
|
||||
return moves
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<odoo>
|
||||
|
||||
<record id="view_sale_stock_invoice_onshipping" model="ir.ui.view">
|
||||
<field name="name">Sale Stock Invoice Onshipping</field>
|
||||
<field name="model">stock.invoice.onshipping</field>
|
||||
<field
|
||||
name="inherit_id"
|
||||
ref="stock_picking_invoicing.view_stock_invoice_onshipping"
|
||||
/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="group" position="after">
|
||||
|
||||
<field name="has_down_payments" invisible="1" />
|
||||
<label
|
||||
for="deduct_down_payments"
|
||||
string=""
|
||||
attrs="{'invisible': [('has_down_payments', '=', False)]}"
|
||||
/>
|
||||
<div
|
||||
attrs="{'invisible': [('has_down_payments', '=', False)]}"
|
||||
id="down_payment_details"
|
||||
>
|
||||
<field name="deduct_down_payments" nolabel="1" />
|
||||
<label for="deduct_down_payments" />
|
||||
</div>
|
||||
|
||||
|
||||
</field>
|
||||
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
Loading…
Add table
Add a link
Reference in a new issue