diff --git a/modules/purchase/CHANGELOG b/modules/purchase/CHANGELOG
index 4987b9d68d..9df4f63cdc 100644
--- a/modules/purchase/CHANGELOG
+++ b/modules/purchase/CHANGELOG
@@ -1,3 +1,4 @@
+* Add relate to purchase lines from party and product
* Simplify relate to purchases
* Prevent creation of lines for non draft purchases
* Allow searching reporting records by name
diff --git a/modules/purchase/purchase.py b/modules/purchase/purchase.py
index ad2b75c368..972b3690fe 100644
--- a/modules/purchase/purchase.py
+++ b/modules/purchase/purchase.py
@@ -1066,7 +1066,7 @@ class Line(sequence_ordered(), ModelSQL, ModelView):
actual_quantity = fields.Float(
"Actual Quantity", digits='unit', readonly=True,
states={
- 'invisible': Eval('type') != 'line',
+ 'invisible': ((Eval('type') != 'line') | ~Eval('actual_quantity')),
})
unit = fields.Many2One('product.uom', 'Unit',
ondelete='RESTRICT',
@@ -1205,10 +1205,20 @@ class Line(sequence_ordered(), ModelSQL, ModelView):
})
purchase_state = fields.Function(
fields.Selection('get_purchase_states', 'Purchase State'),
- 'on_change_with_purchase_state')
+ 'on_change_with_purchase_state', searcher='search_purchase_state')
company = fields.Function(
fields.Many2One('company.company', "Company"),
'on_change_with_company')
+ supplier = fields.Function(
+ fields.Many2One(
+ 'party.party', "Supplier",
+ context={
+ 'company': Eval('company', -1),
+ }),
+ 'on_change_with_supplier', searcher='search_supplier')
+ purchase_date = fields.Function(
+ fields.Date("Purchase Date"),
+ 'on_change_with_purchase_date', searcher='search_purchase_date')
currency = fields.Function(
fields.Many2One('currency.currency', 'Currency'),
'on_change_with_currency')
@@ -1223,6 +1233,8 @@ class Line(sequence_ordered(), ModelSQL, ModelView):
def __setup__(cls):
super().__setup__()
cls.__access__.add('purchase')
+ cls._order.insert(0, ('purchase.purchase_date', 'DESC NULLS FIRST'))
+ cls._order.insert(1, ('purchase.id', 'DESC'))
@classmethod
def __register__(cls, module_name):
@@ -1517,11 +1529,38 @@ class Line(sequence_ordered(), ModelSQL, ModelView):
if self.purchase:
return self.purchase.state
+ @classmethod
+ def search_purchase_state(cls, name, clause):
+ return [('purchase.state', *clause[1:])]
+
@fields.depends('purchase', '_parent_purchase.company')
def on_change_with_company(self, name=None):
if self.purchase and self.purchase.company:
return self.purchase.company.id
+ @fields.depends('purchase', '_parent_purchase.party')
+ def on_change_with_supplier(self, name=None):
+ if self.purchase and self.purchase.party:
+ return self.purchase.party.id
+
+ @classmethod
+ def search_supplier(cls, name, clause):
+ return [('purchase.party' + clause[0][len(name):], *clause[1:])]
+
+ @fields.depends('purchase', '_parent_purchase.purchase_date')
+ def on_change_with_purchase_date(self, name=None):
+ if self.purchase:
+ return self.purchase.purchase_date
+
+ @classmethod
+ def search_purchase_date(cls, name, clause):
+ return [('purchase.purchase_date', *clause[1:])]
+
+ @classmethod
+ def order_purchase_date(cls, tables):
+ return cls.purchase.convert_order(
+ 'purchase.purchase_date', tables, cls)
+
@fields.depends('purchase', '_parent_purchase.currency')
def on_change_with_currency(self, name=None):
if self.purchase and self.purchase.currency:
diff --git a/modules/purchase/purchase.xml b/modules/purchase/purchase.xml
index b8d3d949a8..63dd7f7331 100644
--- a/modules/purchase/purchase.xml
+++ b/modules/purchase/purchase.xml
@@ -435,6 +435,74 @@ this repository contains the full copyright notices and license terms. -->
purchase_line_tree_sequence
+
+ Purchase Lines
+ purchase.line
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Pending
+
+
+
+
+
+
+ Done
+
+
+
+
+
+
+ All
+
+
+
+
+
+ form_relate
+ purchase.purchase,-1
+
+
+
+ form_relate
+ product.product,-1
+
+
+
+ form_relate
+ product.template,-1
+
+
+
+ form_relate
+ party.party,-1
+
+
+
diff --git a/modules/purchase/view/party_form.xml b/modules/purchase/view/party_form.xml
index 956587a63e..5baf42b7cd 100644
--- a/modules/purchase/view/party_form.xml
+++ b/modules/purchase/view/party_form.xml
@@ -4,6 +4,7 @@ this repository contains the full copyright notices and license terms. -->
+
diff --git a/modules/purchase/view/purchase_line_tree.xml b/modules/purchase/view/purchase_line_tree.xml
index 2c4704a5ac..f7ebffaed6 100644
--- a/modules/purchase/view/purchase_line_tree.xml
+++ b/modules/purchase/view/purchase_line_tree.xml
@@ -3,12 +3,15 @@
this repository contains the full copyright notices and license terms. -->
+
+
-
+
+
-
+
diff --git a/modules/purchase/view/template_form.xml b/modules/purchase/view/template_form.xml
index e7931d5cb4..88bee12213 100644
--- a/modules/purchase/view/template_form.xml
+++ b/modules/purchase/view/template_form.xml
@@ -16,6 +16,10 @@ this repository contains the full copyright notices and license terms. -->
+
+
+
+
diff --git a/modules/sale/CHANGELOG b/modules/sale/CHANGELOG
index 5a9c94b8ed..4423edf490 100644
--- a/modules/sale/CHANGELOG
+++ b/modules/sale/CHANGELOG
@@ -1,3 +1,4 @@
+* Add relate to sale lines from party and product
* Simplify relate to sales
* Prevent creation of lines for non draft sales
* Allow searching reporting records by name
diff --git a/modules/sale/sale.py b/modules/sale/sale.py
index c5ecc179fd..00375e2d50 100644
--- a/modules/sale/sale.py
+++ b/modules/sale/sale.py
@@ -1153,7 +1153,7 @@ class SaleLine(TaxableMixin, sequence_ordered(), ModelSQL, ModelView):
actual_quantity = fields.Float(
"Actual Quantity", digits='unit', readonly=True,
states={
- 'invisible': Eval('type') != 'line',
+ 'invisible': ((Eval('type') != 'line') | ~Eval('actual_quantity')),
})
unit = fields.Many2One('product.uom', 'Unit', ondelete='RESTRICT',
states={
@@ -1255,10 +1255,20 @@ class SaleLine(TaxableMixin, sequence_ordered(), ModelSQL, ModelView):
'on_change_with_shipping_date')
sale_state = fields.Function(
fields.Selection('get_sale_states', "Sale State"),
- 'on_change_with_sale_state')
+ 'on_change_with_sale_state', searcher='search_sale_state')
company = fields.Function(
fields.Many2One('company.company', "Company"),
'on_change_with_company')
+ customer = fields.Function(
+ fields.Many2One(
+ 'party.party', "Customer",
+ context={
+ 'company': Eval('company', -1),
+ }),
+ 'on_change_with_customer', searcher='search_customer')
+ sale_date = fields.Function(
+ fields.Date("Sale Date"),
+ 'on_change_with_sale_date', searcher='search_sale_date')
@classmethod
def get_move_product_types(cls):
@@ -1270,6 +1280,8 @@ class SaleLine(TaxableMixin, sequence_ordered(), ModelSQL, ModelView):
def __setup__(cls):
super().__setup__()
cls.__access__.add('sale')
+ cls._order.insert(0, ('sale.sale_date', 'DESC NULLS FIRST'))
+ cls._order.insert(1, ('sale.id', 'DESC'))
@classmethod
def __register__(cls, module_name):
@@ -1536,11 +1548,37 @@ class SaleLine(TaxableMixin, sequence_ordered(), ModelSQL, ModelView):
if self.sale:
return self.sale.state
+ @classmethod
+ def search_sale_state(cls, name, clause):
+ return [('sale.state', *clause[1:])]
+
@fields.depends('sale', '_parent_sale.company')
def on_change_with_company(self, name=None):
if self.sale and self.sale.company:
return self.sale.company.id
+ @fields.depends('sale', '_parent_sale.party')
+ def on_change_with_customer(self, name=None):
+ if self.sale and self.sale.party:
+ return self.sale.party.id
+
+ @classmethod
+ def search_customer(cls, name, clause):
+ return [('sale.party' + clause[0][len(name):], *clause[1:])]
+
+ @fields.depends('sale', '_parent_sale.sale_date')
+ def on_change_with_sale_date(self, name=None):
+ if self.sale:
+ return self.sale.sale_date
+
+ @classmethod
+ def search_sale_date(cls, name, clause):
+ return [('sale.sale_date', *clause[1:])]
+
+ @classmethod
+ def order_sale_date(cls, tables):
+ return cls.sale.convert_order('sale.sale_date', tables, cls)
+
def get_invoice_line(self):
'Return a list of invoice lines for sale line'
pool = Pool()
diff --git a/modules/sale/sale.xml b/modules/sale/sale.xml
index 1bd77698dc..c5f362d657 100644
--- a/modules/sale/sale.xml
+++ b/modules/sale/sale.xml
@@ -419,6 +419,74 @@ this repository contains the full copyright notices and license terms. -->
sale_line_tree_sequence
+
+ Sale Lines
+ sale.line
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Pending
+
+
+
+
+
+
+ Done
+
+
+
+
+
+
+ All
+
+
+
+
+
+ form_relate
+ sale.sale,-1
+
+
+
+ form_relate
+ product.product,-1
+
+
+
+ form_relate
+ product.template,-1
+
+
+
+ form_relate
+ party.party,-1
+
+
+
sale.return_sale.start
form
diff --git a/modules/sale/view/party_form.xml b/modules/sale/view/party_form.xml
index 23b5098291..ff63233c6d 100644
--- a/modules/sale/view/party_form.xml
+++ b/modules/sale/view/party_form.xml
@@ -4,6 +4,7 @@ this repository contains the full copyright notices and license terms. -->
+
diff --git a/modules/sale/view/sale_line_tree.xml b/modules/sale/view/sale_line_tree.xml
index 2836c9272f..9907150946 100644
--- a/modules/sale/view/sale_line_tree.xml
+++ b/modules/sale/view/sale_line_tree.xml
@@ -3,11 +3,14 @@
this repository contains the full copyright notices and license terms. -->
+
+
-
+
+
-
+
diff --git a/modules/sale/view/template_form.xml b/modules/sale/view/template_form.xml
index dbb109423d..a0f5c9130b 100644
--- a/modules/sale/view/template_form.xml
+++ b/modules/sale/view/template_form.xml
@@ -15,6 +15,10 @@ this repository contains the full copyright notices and license terms. -->
+
+
+
+