Skip to content

Commit

Permalink
add taxes and unit price from blanket order
Browse files Browse the repository at this point in the history
  • Loading branch information
JordiBForgeFlow authored and OCA-git-bot committed Jul 16, 2019
1 parent 1f92be5 commit 0a113d1
Show file tree
Hide file tree
Showing 17 changed files with 180 additions and 51 deletions.
3 changes: 2 additions & 1 deletion purchase_blanket_order/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -107,12 +107,13 @@ Credits
Authors
~~~~~~~

* Eficent S.L.
* Eficent

Contributors
~~~~~~~~~~~~

* Adrià Gil Sorribes <adria.gil@eficent.com>
* Jordi Ballester Alomar <jordi.ballester@eficent.com>

Maintainers
~~~~~~~~~~~
Expand Down
4 changes: 2 additions & 2 deletions purchase_blanket_order/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@
'data/ir_cron.xml',
'wizard/create_purchase_orders.xml',
'views/purchase_config_settings.xml',
'views/blanket_orders.xml',
'views/purchase_orders.xml',
'views/purchase_blanket_order_views.xml',
'views/purchase_order_views.xml',
'report/templates.xml',
'report/report.xml',
],
Expand Down
58 changes: 41 additions & 17 deletions purchase_blanket_order/models/blanket_orders.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,11 @@ def _amount_all(self):
compute='_compute_line_count',
readonly=True
)
product_id = fields.Many2one('product.product',
related='line_ids.product_id',
string='Product')
product_id = fields.Many2one(
'product.product',
related='line_ids.product_id',
string='Product',
)
currency_id = fields.Many2one(
'res.currency', required=True,
default=lambda self: self.env.user.company_id.currency_id.id)
Expand All @@ -74,12 +76,14 @@ def _amount_all(self):
track_visibility='always',
help="Date until which the blanket order will be valid, after this "
"date the blanket order will be marked as expired")
date_order = fields.Datetime(
date_start = fields.Datetime(
readonly=True,
required=True,
string='Ordering Date',
string='Start Date',
default=fields.Datetime.now,
states={'draft': [('readonly', False)]})
states={'draft': [('readonly', False)]},
help="Blanket Order starting date."
)
note = fields.Text(
readonly=True,
states={'draft': [('readonly', False)]})
Expand Down Expand Up @@ -192,6 +196,15 @@ def onchange_partner_id(self):
if self.partner_id.user_id:
self.user_id = self.partner_id.user_id.id

@api.multi
def unlink(self):
for order in self:
if order.state not in ('draft', 'cancel'):
raise UserError(_(
'You can not delete an open blanket order! '
'Try to cancel it before.'))
return super(BlanketOrder, self).unlink()

@api.multi
def copy_data(self, default=None):
if default is None:
Expand Down Expand Up @@ -234,6 +247,13 @@ def action_confirm(self):
@api.multi
def action_cancel(self):
for order in self:
if order.purchase_count > 0:
for po in order._get_purchase_orders():
if po.state not in ('cancel'):
raise UserError(_(
'You can not delete a blanket order with opened '
'purchase orders! '
'Try to cancel them before.'))
order.write({'state': 'expired'})
return True

Expand Down Expand Up @@ -345,7 +365,8 @@ def _compute_amount(self):
order_id = fields.Many2one(
'purchase.blanket.order', required=True, ondelete='cascade')
product_id = fields.Many2one(
'product.product', string='Product', required=True)
'product.product', string='Product', required=True,
domain=[('purchase_ok', '=', True)])
product_uom = fields.Many2one(
'product.uom', string='Unit of Measure', required=True)
price_unit = fields.Float(string='Price', required=True,
Expand All @@ -359,19 +380,19 @@ def _compute_amount(self):
digits=dp.get_precision('Product Unit of Measure'))
ordered_uom_qty = fields.Float(
string='Ordered quantity', compute='_compute_quantities',
store=True)
store=True, digits=dp.get_precision('Product Unit of Measure'))
invoiced_uom_qty = fields.Float(
string='Invoiced quantity', compute='_compute_quantities',
store=True)
store=True, digits=dp.get_precision('Product Unit of Measure'))
remaining_uom_qty = fields.Float(
string='Remaining quantity', compute='_compute_quantities',
store=True)
store=True, digits=dp.get_precision('Product Unit of Measure'))
remaining_qty = fields.Float(
string='Remaining quantity in base UoM', compute='_compute_quantities',
store=True)
store=True, digits=dp.get_precision('Product Unit of Measure'))
received_uom_qty = fields.Float(
string='Received quantity', compute='_compute_quantities',
store=True)
store=True, digits=dp.get_precision('Product Unit of Measure'))
purchase_lines = fields.One2many(
comodel_name='purchase.order.line',
inverse_name='blanket_order_line',
Expand Down Expand Up @@ -416,7 +437,9 @@ def name_get(self):
formatted_date = self._format_date(record.date_schedule)
res += ' - %s: %s' % (
_('Date Scheduled'), formatted_date)
res += ' (%s: %s)' % (_('remaining'), record.remaining_uom_qty)
res += ' (%s: %s %s)' % (_('remaining'),
record.remaining_uom_qty,
record.product_uom.name)
result.append((record.id, res))
return result
return super(BlanketOrderLine, self).name_get()
Expand All @@ -427,7 +450,7 @@ def _get_display_price(self, product):
seller = product._select_seller(
partner_id=self.order_id.partner_id,
quantity=self.original_uom_qty,
date=self.order_id.date_order and self.order_id.date_order[:10],
date=self.order_id.date_start and self.order_id.date_start[:10],
uom_id=self.product_uom)

if not seller:
Expand Down Expand Up @@ -456,7 +479,8 @@ def onchange_product(self):
'Product Unit of Measure')
if self.product_id:
name = self.product_id.name
self.product_uom = self.product_id.uom_id.id
if not self.product_uom:
self.product_uom = self.product_id.uom_id.id
if self.order_id.partner_id and \
float_is_zero(self.price_unit, precision_digits=precision):
self.price_unit = self._get_display_price(self.product_id)
Expand Down Expand Up @@ -506,8 +530,8 @@ def _compute_quantities(self):
l.product_id == line.product_id)
line.remaining_uom_qty = line.original_uom_qty - \
line.ordered_uom_qty
line.remaining_qty = line.product_id.uom_id._compute_quantity(
line.remaining_uom_qty, line.product_uom)
line.remaining_qty = line.product_uom._compute_quantity(
line.remaining_uom_qty, line.product_id.uom_id)

@api.multi
def _validate(self):
Expand Down
55 changes: 43 additions & 12 deletions purchase_blanket_order/models/purchase_order.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,24 +55,33 @@ def _get_assigned_bo_line(self, bo_lines):
date_planned = fields.Date.from_string(self.date_planned) or \
date.today()
date_delta = timedelta(days=365)
for line in bo_lines:
for line in bo_lines.filtered(lambda l: l.date_schedule):
date_schedule = fields.Date.from_string(line.date_schedule)
if date_schedule and \
abs(date_schedule - date_planned) < date_delta:
assigned_bo_line = line
date_delta = abs(date_schedule - date_planned)
return assigned_bo_line
if assigned_bo_line:
return assigned_bo_line
non_date_bo_lines = bo_lines.filtered(lambda l: not l.date_schedule)
if non_date_bo_lines:
return non_date_bo_lines[0]

def _get_eligible_bo_lines(self):
base_qty = self.product_uom._compute_quantity(
self.product_qty, self.product_id.uom_id)
def _get_eligible_bo_lines_domain(self, base_qty):
filters = [
('product_id', '=', self.product_id.id),
('remaining_qty', '>=', base_qty),
('currency_id', '=', self.order_id.currency_id.id),
('order_id.state', '=', 'open')]
if self.order_id.partner_id:
filters.append(
('partner_id', '=', self.order_id.partner_id.id))
return filters

def _get_eligible_bo_lines(self):
base_qty = self.product_uom._compute_quantity(
self.product_qty, self.product_id.uom_id)
filters = self._get_eligible_bo_lines_domain(base_qty)
return self.env['purchase.blanket.order.line'].search(filters)

@api.multi
Expand All @@ -86,6 +95,7 @@ def get_assigned_bo_line(self):
self._get_assigned_bo_line(eligible_bo_lines)
else:
self.blanket_order_line = False
self.onchange_blanket_order_line()
return {'domain': {'blanket_order_line': [
('id', 'in', eligible_bo_lines.ids)]}}

Expand All @@ -100,18 +110,29 @@ def onchange_product_id(self):
@api.onchange('product_qty', 'product_uom')
def _onchange_quantity(self):
res = super(PurchaseOrderLine, self)._onchange_quantity()
if self.product_id:
if self.product_id and not self.env.context.get(
'skip_blanket_find', False):
return self.get_assigned_bo_line()
return res

@api.onchange('blanket_order_line')
def onchange_blanket_order_line(self):
if self.blanket_order_line:
self.product_id = self.blanket_order_line.product_id
if self.blanket_order_line.date_schedule:
self.date_planned = self.blanket_order_line.date_schedule
if self.blanket_order_line.price_unit:
self.price_unit = self.blanket_order_line.price_unit
bol = self.blanket_order_line
if bol:
self.product_id = bol.product_id
if bol.date_schedule:
self.date_planned = bol.date_schedule
if bol.product_uom != self.product_uom:
price_unit = bol.product_uom._compute_price(
bol.price_unit, self.product_uom)
else:
price_unit = bol.price_unit
self.price_unit = price_unit
if bol.taxes_id:
self.taxes_id = bol.taxes_id
else:
self._compute_tax_id()
self.with_context(skip_blanket_find=True)._onchange_quantity()

@api.constrains('date_planned')
def check_date_planned(self):
Expand All @@ -124,3 +145,13 @@ def check_date_planned(self):
raise ValidationError(_(
'Schedule dates defined on the Purchase Order Line '
'and on the Blanket Order Line do not match.'))

@api.constrains('currency_id')
def check_currency(self):
for line in self:
blanket_currency = line.blanket_order_line.order_id.currency_id
if blanket_currency and line.order_id.currency_id != \
blanket_currency:
raise ValidationError(_(
'The currency of the blanket order must match with that '
'of the purchase order.'))
1 change: 1 addition & 0 deletions purchase_blanket_order/readme/CONTRIBUTORS.rst
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
* Adrià Gil Sorribes <adria.gil@eficent.com>
* Jordi Ballester Alomar <jordi.ballester@eficent.com>
Binary file modified purchase_blanket_order/static/description/BO_actions.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified purchase_blanket_order/static/description/BO_form.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified purchase_blanket_order/static/description/BO_lines.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified purchase_blanket_order/static/description/BO_menu.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified purchase_blanket_order/static/description/PO_BOLine.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified purchase_blanket_order/static/description/PO_from_BO.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 2 additions & 1 deletion purchase_blanket_order/static/description/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -425,13 +425,14 @@ <h1><a class="toc-backref" href="#id3">Credits</a></h1>
<div class="section" id="authors">
<h2><a class="toc-backref" href="#id4">Authors</a></h2>
<ul class="simple">
<li>Eficent S.L.</li>
<li>Eficent</li>
</ul>
</div>
<div class="section" id="contributors">
<h2><a class="toc-backref" href="#id5">Contributors</a></h2>
<ul class="simple">
<li>Adrià Gil Sorribes &lt;<a class="reference external" href="mailto:adria.gil&#64;eficent.com">adria.gil&#64;eficent.com</a>&gt;</li>
<li>Jordi Ballester Alomar &lt;<a class="reference external" href="mailto:jordi.ballester&#64;eficent.com">jordi.ballester&#64;eficent.com</a>&gt;</li>
</ul>
</div>
<div class="section" id="maintainers">
Expand Down
70 changes: 67 additions & 3 deletions purchase_blanket_order/tests/test_purchase_order.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,20 @@ def setUp(self):
'uom_id': self.env.ref('product.product_uom_unit').id,
'default_code': 'PROD_DEL01',
})
self.product_2 = self.env['product.product'].create({
'name': 'Demo 2',
'categ_id': self.env.ref('product.product_category_1').id,
'standard_price': 35.0,
'seller_ids': [(6, 0, [seller.id])],
'type': 'consu',
'uom_id': self.env.ref('product.product_uom_unit').id,
'default_code': 'PROD_DEL02',
})
self.validity = date.today() + timedelta(days=365)
self.date_schedule_1 = date.today() + timedelta(days=10)
self.date_schedule_2 = date.today() + timedelta(days=20)

def create_blanket_order(self):
def create_blanket_order_01(self):
blanket_order = self.blanket_order_obj.create({
'partner_id': self.partner.id,
'validity_date': fields.Date.to_string(self.validity),
Expand All @@ -62,10 +71,32 @@ def create_blanket_order(self):
blanket_order.sudo().onchange_partner_id()
return blanket_order

def create_blanket_order_02(self):
blanket_order = self.blanket_order_obj.create({
'partner_id': self.partner.id,
'validity_date': fields.Date.to_string(self.validity),
'payment_term_id': self.payment_term.id,
'line_ids': [(0, 0, {
'product_id': self.product.id,
'product_uom': self.product.uom_id.id,
'original_uom_qty': 20.0,
'price_unit': 30.0,
}), (0, 0, {
'product_id': self.product_2.id,
'product_uom': self.product.uom_id.id,
'original_uom_qty': 20.0,
'price_unit': 30.0,
})],
})
blanket_order.sudo().onchange_partner_id()
return blanket_order

def test_01_create_purchase_order(self):
blanket_order = self.create_blanket_order()
blanket_order = self.create_blanket_order_01()
blanket_order.sudo().action_confirm()
bo_lines = self.blanket_order_line_obj.search([])
bo_lines = self.blanket_order_line_obj.search([
('order_id', '=', blanket_order.id),
])
self.assertEqual(len(bo_lines), 2)

po = self.purchase_order_obj.create({
Expand All @@ -89,3 +120,36 @@ def test_01_create_purchase_order(self):
('date_schedule', '=', fields.Date.to_string(self.date_schedule_1))
])
self.assertEqual(po_line.blanket_order_line, bo_line_assigned)

def test_02_create_purchase_order(self):
blanket_order = self.create_blanket_order_02()
blanket_order.sudo().action_confirm()
bo_lines = self.blanket_order_line_obj.search([
('order_id', '=', blanket_order.id),
])
self.assertEqual(len(bo_lines), 2)

po = self.purchase_order_obj.create({
'partner_id': self.partner.id,
'order_line': [
(0, 0, {
'name': self.product.name,
'product_id': self.product.id,
'product_qty': 5.0,
'product_uom': self.product.uom_po_id.id,
'date_planned': date.today(),
'price_unit': 10.0,
})
]
})
po_line = po.order_line[0]
po_line.with_context(from_purchase_order=True).name_get()
po_line.onchange_product_id()
self.assertEqual(po_line._get_eligible_bo_lines(), bo_lines.filtered(
lambda l: l.product_id == self.product))
bo_line_assigned = self.blanket_order_line_obj.search([
('order_id', '=', blanket_order.id),
('product_id', '=', self.product.id),
('date_schedule', '=', False)
])
self.assertEqual(po_line.blanket_order_line, bo_line_assigned)
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@
</group>
<group name="group_bottom">
<group name="group_bottom_left">
<field name="date_order" attrs="{'required': [('state', '=', 'draft')]}"/>
<field name="date_start" attrs="{'required': [('state', '=', 'draft')]}"/>
</group>
<group name="group_bottom_right">
<field name="validity_date" attrs="{'required': [('state', '=', 'draft')]}"/>
Expand All @@ -89,7 +89,7 @@
string="Original Qty"
context="{'partner_id':parent.partner_id, 'quantity':original_uom_qty, 'company_id': parent.company_id}"
/>
<field name="product_uom"/>
<field name="product_uom" groups="product.group_uom"/>
<field name="price_unit"/>
<field name="date_schedule"/>
<field name="ordered_uom_qty"/>
Expand Down

0 comments on commit 0a113d1

Please sign in to comment.