Skip to content

Commit b004737

Browse files
kittiuAungKoKoLin1997
authored andcommitted
[12.0][ADD] purchase_deposit
1 parent 4264684 commit b004737

17 files changed

+537
-0
lines changed

purchase_deposit/__init__.py

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Copyright 2019 Elico Corp, Dominique K. <dominique.k@elico-corp.com.sg>
2+
# Copyright 2019 Ecosoft Co., Ltd., Kitti U. <kittiu@ecosoft.co.th>
3+
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
4+
5+
from . import models
6+
from . import wizard

purchase_deposit/__manifest__.py

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Copyright 2019 Elico Corp, Dominique K. <dominique.k@elico-corp.com.sg>
2+
# Copyright 2019 Ecosoft Co., Ltd., Kitti U. <kittiu@ecosoft.co.th>
3+
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
4+
5+
{
6+
'name': 'Purchase Deposit',
7+
'version': '12.0.1.0.0',
8+
'summary': 'Option to create deposit from purchase order',
9+
'author': 'Elico Corp, Ecosoft, Odoo Community Association (OCA)',
10+
'website': 'https://github.com/OCA/purchase-workflow',
11+
'category': 'Purchase Management',
12+
'license': 'AGPL-3',
13+
'depends': [
14+
'purchase',
15+
],
16+
'data': [
17+
'wizard/purchase_make_invoice_advance_views.xml',
18+
'views/res_config_settings_views.xml',
19+
'views/purchase_view.xml',
20+
],
21+
'installable': True,
22+
'auto_install': False,
23+
}

purchase_deposit/models/__init__.py

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Copyright 2019 Elico Corp, Dominique K. <dominique.k@elico-corp.com.sg>
2+
# Copyright 2019 Ecosoft Co., Ltd., Kitti U. <kittiu@ecosoft.co.th>
3+
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
4+
5+
from . import res_config_settings
6+
from . import purchase
7+
from . import invoice

purchase_deposit/models/invoice.py

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Copyright 2019 Elico Corp, Dominique K. <dominique.k@elico-corp.com.sg>
2+
# Copyright 2019 Ecosoft Co., Ltd., Kitti U. <kittiu@ecosoft.co.th>
3+
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
4+
5+
from odoo import models
6+
7+
8+
class AccountInvoice(models.Model):
9+
_inherit = 'account.invoice'
10+
11+
def _prepare_invoice_line_from_po_line(self, line):
12+
res = super(AccountInvoice, self).\
13+
_prepare_invoice_line_from_po_line(line)
14+
if line.is_deposit:
15+
res['quantity'] = -1 * line.qty_invoiced
16+
return res

purchase_deposit/models/purchase.py

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Copyright 2019 Elico Corp, Dominique K. <dominique.k@elico-corp.com.sg>
2+
# Copyright 2019 Ecosoft Co., Ltd., Kitti U. <kittiu@ecosoft.co.th>
3+
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
4+
5+
from odoo import api, fields, models
6+
7+
8+
class PurchaseOrder(models.Model):
9+
_inherit = 'purchase.order'
10+
11+
@api.multi
12+
def copy_data(self, default=None):
13+
if default is None:
14+
default = {}
15+
default['order_line'] = \
16+
[(0, 0, line.copy_data()[0])
17+
for line in self.order_line.filtered(lambda l: not l.is_deposit)]
18+
return super(PurchaseOrder, self).copy_data(default)
19+
20+
21+
class PurchaseOrderLine(models.Model):
22+
_inherit = 'purchase.order.line'
23+
24+
is_deposit = fields.Boolean(
25+
string='Is a deposit payment',
26+
help="Deposit payments are made when creating invoices from a purhcase"
27+
" order. They are not copied when duplicating a purchase order.",
28+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Copyright 2019 Elico Corp, Dominique K. <dominique.k@elico-corp.com.sg>
2+
# Copyright 2019 Ecosoft Co., Ltd., Kitti U. <kittiu@ecosoft.co.th>
3+
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
4+
5+
from odoo import models, fields
6+
7+
8+
class ResConfigSettings(models.TransientModel):
9+
_inherit = 'res.config.settings'
10+
11+
default_purchase_deposit_product_id = fields.Many2one(
12+
comodel_name='product.product',
13+
string='Purchase Deposit Product',
14+
default_model='purchase.advance.payment.inv',
15+
domain=[('type', '=', 'service')],
16+
help="Default product used for payment advances.",
17+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
After install this module, you need to select the product "Purchase Deposit" in
2+
configuration window to be used as default product when create deposit invoice.
3+
4+
Go to Purchase > Configuration > Settings, then select product "Purchase Deposit"
5+
6+
Note: If this is not done, by using "Register Deposit" for the first time will
7+
also create product "Purchase Deposit" for you automatically.
+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
* Dominique K. <dominique.k@elico-corp.com.sg>
2+
* Kitti Upariphutthiphong <kittiu@ecosoft.co.th>
+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
This module allow purchase order to register deposit similar to that in sales order

purchase_deposit/readme/USAGE.rst

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
When purchase order is confirmed, a new button "Register Deposit" will appear.
2+
Normally, deposit will be used to create the 1st invoice (as deposit).
3+
4+
#. On confirmed purchase order, click Register Deposit button, wizard will open
5+
#. 2 type of deposit invoice can be create 1) Down Payment (percentage) 2) Deposit Payment (fixed amount)
6+
#. Fill in the value and click Create Invoice button.
7+
8+
As deposit is created, when user click button "Create Bill" again in purchase order,
9+
the Vendor Bill will be created with deposit amount deducted.

purchase_deposit/tests/__init__.py

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Copyright 2019 Elico Corp, Dominique K. <dominique.k@elico-corp.com.sg>
2+
# Copyright 2019 Ecosoft Co., Ltd., Kitti U. <kittiu@ecosoft.co.th>
3+
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
4+
5+
from . import test_purchase_deposit
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
# Copyright 2019 Elico Corp, Dominique K. <dominique.k@elico-corp.com.sg>
2+
# Copyright 2019 Ecosoft Co., Ltd., Kitti U. <kittiu@ecosoft.co.th>
3+
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
4+
5+
from odoo import fields
6+
from odoo.tests.common import TransactionCase
7+
from odoo.exceptions import UserError
8+
from odoo.tests.common import Form
9+
10+
11+
class TestPurchaseDeposit(TransactionCase):
12+
13+
def setUp(self):
14+
super(TestPurchaseDeposit, self).setUp()
15+
self.product_model = self.env['product.product']
16+
self.account_model = self.env['account.account']
17+
self.invoice_model = self.env['account.invoice']
18+
self.default_model = self.env['ir.default']
19+
20+
# Create Deposit Account
21+
self.account_deposit = self.account_model.create({
22+
'name': 'Purchase Deposit',
23+
'code': '11620',
24+
'user_type_id': self.env.ref(
25+
'account.data_account_type_current_assets').id,
26+
})
27+
# Create products:
28+
p1 = self.product1 = self.product_model.create({
29+
'name': 'Test Product 1',
30+
'type': 'service',
31+
'default_code': 'PROD1',
32+
'purchase_method': 'purchase',
33+
})
34+
35+
self.po = self.env['purchase.order'].create({
36+
'partner_id': self.ref('base.res_partner_3'),
37+
'order_line': [
38+
(0, 0, {'product_id': p1.id,
39+
'product_uom': p1.uom_id.id,
40+
'name': p1.name,
41+
'price_unit': 100.0,
42+
'date_planned': fields.Datetime.now(),
43+
'product_qty': 42.0})]})
44+
45+
def test_create_deposit_invoice(self):
46+
self.assertEqual(len(self.po.order_line), 1)
47+
# We create invoice from expense
48+
ctx = {'active_id': self.po.id,
49+
'active_ids': [self.po.id],
50+
'active_model': 'purchase.order'}
51+
CreateDeposit = self.env['purchase.advance.payment.inv']
52+
self.po.button_confirm()
53+
with Form(CreateDeposit.with_context(ctx)) as f:
54+
f.advance_payment_method = 'percentage'
55+
f.deposit_account_id = self.account_deposit
56+
wizard = f.save()
57+
wizard.amount = 10.0 # 10%
58+
wizard.create_invoices()
59+
# New Purchase Deposit is created automatically
60+
deposit_id = self.default_model.get('purchase.advance.payment.inv',
61+
'purchase_deposit_product_id')
62+
deposit = self.product_model.browse(deposit_id)
63+
self.assertEqual(deposit.name, 'Purchase Deposit')
64+
# 1 Deposit Invoice is created
65+
self.assertRecordValues(self.po.invoice_ids.invoice_line_ids, [
66+
{'product_id': deposit.id,
67+
'price_unit': 420.0, 'name': 'Deposit Payment', },
68+
])
69+
# On Purchase Order, there will be new deposit line create
70+
self.assertRecordValues(self.po.order_line, [
71+
{'product_id': self.product1.id,
72+
'price_unit': 100.0, 'is_deposit': False},
73+
{'product_id': deposit.id,
74+
'price_unit': 420.0, 'is_deposit': True},
75+
])
76+
# On Purchase Order, create normal billing
77+
res = self.po.with_context(create_bill=True).action_view_invoice()
78+
ctx = res.get('context')
79+
f = Form(self.invoice_model.with_context(ctx),
80+
view='account.invoice_supplier_form')
81+
invoice = f.save()
82+
self.assertRecordValues(invoice.invoice_line_ids, [
83+
{'product_id': self.product1.id,
84+
'price_unit': 100.0, 'quantity': 42},
85+
{'product_id': deposit.id,
86+
'price_unit': 420.0, 'quantity': -1},
87+
])
88+
89+
def test_create_deposit_invoice_exception(self):
90+
"""This test focus on exception cases, when create deposit invoice,
91+
1. This action is allowed only in Purchase Order sate
92+
2. The value of the deposit must be positive
93+
3. For type percentage, The percentage of the deposit must <= 100
94+
4. Purchase Deposit Product's purchase_method != purchase
95+
5. Purchase Deposit Product's type != service
96+
"""
97+
self.assertEqual(len(self.po.order_line), 1)
98+
# We create invoice from expense
99+
ctx = {'active_id': self.po.id,
100+
'active_ids': [self.po.id],
101+
'active_model': 'purchase.order'}
102+
CreateDeposit = self.env['purchase.advance.payment.inv']
103+
# 1. This action is allowed only in Purchase Order sate
104+
with self.assertRaises(UserError):
105+
Form(CreateDeposit.with_context(ctx)) # Initi wizard
106+
self.po.button_confirm()
107+
self.assertEqual(self.po.state, 'purchase')
108+
# 2. The value of the deposit must be positive
109+
f = Form(CreateDeposit.with_context(ctx))
110+
f.advance_payment_method = 'fixed'
111+
f.amount = 0.0
112+
f.deposit_account_id = self.account_deposit
113+
wizard = f.save()
114+
with self.assertRaises(UserError):
115+
wizard.create_invoices()
116+
# 3. For type percentage, The percentage of the deposit must <= 100
117+
wizard.advance_payment_method = 'percentage'
118+
wizard.amount = 101.0
119+
with self.assertRaises(UserError):
120+
wizard.create_invoices()
121+
wizard.amount = 10
122+
# 4. Purchase Deposit Product's purchase_method != purchase
123+
deposit_id = self.default_model.get('purchase.advance.payment.inv',
124+
'purchase_deposit_product_id')
125+
deposit = self.product_model.browse(deposit_id)
126+
deposit.purchase_method = 'receive'
127+
wizard.purchase_deposit_product_id = deposit
128+
with self.assertRaises(UserError):
129+
wizard.create_invoices()
130+
deposit.purchase_method = 'purchase'
131+
# 5. Purchase Deposit Product's type != service
132+
deposit.type = 'consu'
133+
with self.assertRaises(UserError):
134+
wizard.create_invoices()
+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<odoo>
3+
4+
<record id="view_purchase_order_form_inherit" model="ir.ui.view">
5+
<field name="name">view.purchase.order.inherit</field>
6+
<field name="model">purchase.order</field>
7+
<field name="type">form</field>
8+
<field name="inherit_id" ref="purchase.purchase_order_form"/>
9+
<field name="arch" type="xml">
10+
<xpath expr="//button[@name='button_cancel']" position="before">
11+
<button name="%(purchase_deposit.action_view_purchase_advance_payment_inv)d"
12+
states="purchase" type="action" string="Register Deposit"/>
13+
</xpath>
14+
</field>
15+
</record>
16+
17+
</odoo>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<odoo>
3+
4+
<record id="res_config_settings_view_form_purchase" model="ir.ui.view">
5+
<field name="name">res.config.settings.view.form.inherit.purchase</field>
6+
<field name="model">res.config.settings</field>
7+
<field name="priority" eval="25"/>
8+
<field name="inherit_id" ref="purchase.res_config_settings_view_form_purchase"/>
9+
<field name="arch" type="xml">
10+
<xpath expr="//field[@name='module_account_3way_match']/../.." position="after">
11+
<div class="col-xs-12 col-md-6 o_setting_box">
12+
<div class="o_setting_left_pane"/>
13+
<div class="o_setting_right_pane">
14+
<label for="default_purchase_deposit_product_id" string="Deposit Payments"/>
15+
<div class="text-muted">
16+
Product used for deposit payments
17+
</div>
18+
<div class="text-muted">
19+
<field name="default_purchase_deposit_product_id"/>
20+
</div>
21+
</div>
22+
</div>
23+
</xpath>
24+
</field>
25+
</record>
26+
27+
</odoo>

purchase_deposit/wizard/__init__.py

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Copyright 2019 Elico Corp, Dominique K. <dominique.k@elico-corp.com.sg>
2+
# Copyright 2019 Ecosoft Co., Ltd., Kitti U. <kittiu@ecosoft.co.th>
3+
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
4+
5+
from . import purchase_make_invoice_advance

0 commit comments

Comments
 (0)