summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRafi Zadanly <zadanlyr@gmail.com>2024-04-29 09:24:25 +0700
committerRafi Zadanly <zadanlyr@gmail.com>2024-04-29 09:24:25 +0700
commit074b99031f5123976bb67aab1cf1a6286464e724 (patch)
tree2809d42a13b35c42ec00d93a40a414e7713a1bc2
parentb5a42eda62ae2b3536a072b9cb21a61e91a7b49a (diff)
parentca03f0119e33dd62adbf998106378d8e0f4096b6 (diff)
Merge branch 'production' into feature/request-by-abl
-rw-r--r--indoteknik_api/controllers/api_v1/sale_order.py7
-rw-r--r--indoteknik_custom/models/account_move.py24
-rw-r--r--indoteknik_custom/models/automatic_purchase.py25
-rw-r--r--indoteknik_custom/models/commision.py3
-rwxr-xr-xindoteknik_custom/models/crm_lead.py9
-rw-r--r--indoteknik_custom/models/cust_commision.py1
-rw-r--r--indoteknik_custom/models/logbook_sj.py4
-rwxr-xr-xindoteknik_custom/models/purchase_order_line.py44
-rw-r--r--indoteknik_custom/models/report_logbook_sj.py1
-rwxr-xr-xindoteknik_custom/models/sale_order.py3
-rw-r--r--indoteknik_custom/models/solr/promotion_program_line.py5
-rw-r--r--indoteknik_custom/models/voucher.py4
-rw-r--r--indoteknik_custom/views/account_move.xml5
-rw-r--r--indoteknik_custom/views/automatic_purchase.xml4
-rw-r--r--indoteknik_custom/views/cust_commision.xml2
-rw-r--r--indoteknik_custom/views/customer_commision.xml2
-rw-r--r--indoteknik_custom/views/ir_sequence.xml11
-rw-r--r--indoteknik_custom/views/logbook_sj.xml1
-rw-r--r--indoteknik_custom/views/promotion/promotion_program_line.xml8
-rw-r--r--indoteknik_custom/views/report_logbook_sj.xml1
-rwxr-xr-xindoteknik_custom/views/sale_order.xml4
21 files changed, 152 insertions, 16 deletions
diff --git a/indoteknik_api/controllers/api_v1/sale_order.py b/indoteknik_api/controllers/api_v1/sale_order.py
index 3f31011c..957d49c7 100644
--- a/indoteknik_api/controllers/api_v1/sale_order.py
+++ b/indoteknik_api/controllers/api_v1/sale_order.py
@@ -357,12 +357,17 @@ class SaleOrder(controller.Controller):
'carrier_id': params['value']['carrier_id'],
'delivery_service_type': params['value']['delivery_service_type'],
'customer_type': 'nonpkp',
- 'npwp': '0'
+ 'npwp': '0',
+ 'user_id': 1180 # User ID: Ima Nurhikmah
}
if params['value']['type'] == 'sale_order':
parameters['approval_status'] = 'pengajuan1'
sale_order = request.env['sale.order'].create([parameters])
sale_order.onchange_partner_contact()
+
+ sales_partner = sale_order.partner_id.user_id
+ if sales_partner and sales_partner not in [25]: # 25: System
+ parameters['user_id'] = sales_partner.id
user_id = params['value']['user_id']
user_cart = request.env['website.user.cart']
diff --git a/indoteknik_custom/models/account_move.py b/indoteknik_custom/models/account_move.py
index 94a1ab19..b306b6af 100644
--- a/indoteknik_custom/models/account_move.py
+++ b/indoteknik_custom/models/account_move.py
@@ -57,6 +57,30 @@ class AccountMove(models.Model):
is_efaktur_uploaded = fields.Boolean(string="Is eFaktur Uploaded", default=False)
already_paid = fields.Boolean(string="Sudah Dibayar?", default=False)
delivery_amt_text = fields.Char(string="Delivery Amt Terbilang", compute='compute_delivery_amt_text')
+ so_shipping_paid_by = fields.Char(string="SO Shipping Paid By", compute='compute_so_shipping_paid_by')
+ so_shipping_covered_by = fields.Char(string="SO Shipping Covered By", compute='compute_so_shipping_paid_by')
+ so_delivery_amt = fields.Char(string="SO Delivery Amount", compute='compute_so_shipping_paid_by')
+ flag_delivery_amt = fields.Boolean(string="Flag Delivery Amount", compute='compute_flag_delivery_amt')
+ nomor_kwitansi = fields.Char(string="Nomor Kwitansi")
+
+ @api.model
+ def create(self, vals):
+ vals['nomor_kwitansi'] = self.env['ir.sequence'].next_by_code('nomor.kwitansi') or '0'
+ result = super(AccountMove, self).create(vals)
+ return result
+
+ def compute_so_shipping_paid_by(self):
+ for record in self:
+ record.so_shipping_paid_by = record.sale_id.shipping_paid_by
+ record.so_shipping_covered_by = record.sale_id.shipping_cost_covered
+ record.so_delivery_amt = record.sale_id.delivery_amt
+
+ def compute_flag_delivery_amt(self):
+ for record in self:
+ if record.sale_id.delivery_amt > 0:
+ record.flag_delivery_amt = True
+ else:
+ record.flag_delivery_amt = False
def compute_delivery_amt_text(self):
tb = Terbilang()
diff --git a/indoteknik_custom/models/automatic_purchase.py b/indoteknik_custom/models/automatic_purchase.py
index 32a7d9dd..dae1c6a4 100644
--- a/indoteknik_custom/models/automatic_purchase.py
+++ b/indoteknik_custom/models/automatic_purchase.py
@@ -252,14 +252,24 @@ class AutomaticPurchase(models.Model):
'suggest': product._get_po_suggest(line.qty_purchase),
'product_uom_qty': line.qty_purchase,
'price_unit': line.last_price,
+ 'taxes_id': [line.taxes_id.id] if line.taxes_id else None,
# 'so_line_id': [sales.sale_line_id.id for sales in sales_match],
}
new_po_line = self.env['purchase.order.line'].create([param_line])
line.current_po_id = new_po.id
line.current_po_line_id = new_po_line.id
+ self.update_purchase_price_so_line(line)
self.create_purchase_order_sales_match(new_po)
+ def update_purchase_price_so_line(self, apo):
+ sales_match = self.env['automatic.purchase.sales.match'].search([
+ ('automatic_purchase_id', '=', self.id),
+ ('product_id', '=', apo.product_id.id),
+ ])
+
+ for sales in sales_match:
+ sales.sale_line_id.purchase_price = apo.last_price
def create_purchase_order_sales_match(self, purchase_order):
matches_so_product_ids = [line.product_id.id for line in purchase_order.order_line]
@@ -338,6 +348,7 @@ class AutomaticPurchase(models.Model):
purchase_pricelist = self.env['purchase.pricelist'].search(domain, order=orderby, limit=1)
vendor_id = purchase_pricelist.vendor_id
+ taxes = ''
price, taxes = automatic_purchase._get_valid_purchase_price(purchase_pricelist)
last_po_line = self.env['purchase.order.line'].search([('product_id', '=', job.product_id.id), ('order_id.state', '=', 'done')], order='id desc', limit=1)
@@ -359,7 +370,8 @@ class AutomaticPurchase(models.Model):
automatic_purchase.notification = "Automatic PO Created %s Lines" % count
automatic_purchase._create_sales_matching()
automatic_purchase._create_sync_purchasing_job(jobs)
- print(1)
+
+ return automatic_purchase.id
def _create_sales_matching(self):
for line in self.purchase_lines:
@@ -374,6 +386,10 @@ class AutomaticPurchase(models.Model):
('product_id', '=', sale.product_id.id),
])
+ price_so = self.env['sale.order.line'].search([
+ ('id', '=', sale.sale_line_id.id),
+ ])
+
if existing_match:
continue
@@ -389,6 +405,8 @@ class AutomaticPurchase(models.Model):
'product_id': sale.product_id.id,
'qty_so': sale.outgoing,
'qty_po': line.qty_purchase,
+ 'purchase_price': price_so.purchase_price,
+ 'purchase_tax_id': price_so.purchase_tax_id.id if price_so.purchase_tax_id.id else None,
}])
def _create_sync_purchasing_job(self, jobs):
@@ -467,7 +485,7 @@ class AutomaticPurchase(models.Model):
def _get_valid_purchase_price(self, purchase_price):
price = 0
- taxes = None
+ taxes = ''
human_last_update = purchase_price.human_last_update or datetime.min
system_last_update = purchase_price.system_last_update or datetime.min
@@ -540,7 +558,8 @@ class AutomaticPurchaseSalesMatch(models.Model):
product_id = fields.Many2one('product.product', string='Product')
qty_so = fields.Float(string='Qty SO')
qty_po = fields.Float(string='Qty PO')
-
+ purchase_price = fields.Float(string='Purchase Price SO')
+ purchase_tax_id = fields.Many2one('account.tax', string='Tax', domain=['|', ('active', '=', False), ('active', '=', True)])
class SyncPurchasingJob(models.Model):
_name = 'sync.purchasing.job'
diff --git a/indoteknik_custom/models/commision.py b/indoteknik_custom/models/commision.py
index e60fe9a7..7ec2cecc 100644
--- a/indoteknik_custom/models/commision.py
+++ b/indoteknik_custom/models/commision.py
@@ -152,6 +152,7 @@ class CustomerCommision(models.Model):
account_name = fields.Char(string='Account Name', tracking=3)
bank_account = fields.Char(string='Account No', tracking=3)
note_transfer = fields.Char(string='Keterangan')
+ brand_ids = fields.Many2many('x_manufactures', string='Brands')
# add status for type of commision, fee, rebate / cashback
# include child or not?
@@ -250,7 +251,7 @@ class CustomerCommision(models.Model):
partners = rec.partner_ids
for partner in partners:
- brand = [92, 10, 89, 12, 324, 11]
+ brand = [int(brand) for brand in rec.brand_ids]
where = [
('move_id.move_type', '=', 'out_invoice'),
('move_id.state', '=', 'posted'),
diff --git a/indoteknik_custom/models/crm_lead.py b/indoteknik_custom/models/crm_lead.py
index e8721142..9ffd607c 100755
--- a/indoteknik_custom/models/crm_lead.py
+++ b/indoteknik_custom/models/crm_lead.py
@@ -23,6 +23,15 @@ class CrmLead(models.Model):
operator_name = fields.Char('Operator Name', help='Operator yang membalas')
order_id = fields.Many2one('sale.order', string='Sales Order', help='Link ke sales order id')
+ @api.model
+ def create(self, vals):
+ rec = super(CrmLead, self).create(vals)
+
+ if rec.email_from == 'api.noreply@altama.co.id' and rec.name.startswith('INDOTEKNIK|ODOO|'):
+ rec.user_id = 20 # User ID: Nabila Rahmawati
+
+ return rec
+
@api.onchange('user_id')
def _change_salesperson_so(self):
if self.order_id:
diff --git a/indoteknik_custom/models/cust_commision.py b/indoteknik_custom/models/cust_commision.py
index da345f04..c3105cfd 100644
--- a/indoteknik_custom/models/cust_commision.py
+++ b/indoteknik_custom/models/cust_commision.py
@@ -21,6 +21,7 @@ class CustCommision(models.Model):
('cashback', 'Cashback'),
('rebate', 'Rebate'),
], string='Commision Type', required=True)
+ brand_ids = fields.Many2many('x_manufactures', string='Brands', help='Voucher appplied only for brand')
@api.constrains('partner_id')
def _check_partner_id(self):
diff --git a/indoteknik_custom/models/logbook_sj.py b/indoteknik_custom/models/logbook_sj.py
index 9e3daf20..f84619ad 100644
--- a/indoteknik_custom/models/logbook_sj.py
+++ b/indoteknik_custom/models/logbook_sj.py
@@ -40,7 +40,8 @@ class LogbookSJ(models.TransientModel):
'carrier_id': stock.carrier_id.id,
'tracking_no': stock.delivery_tracking_no,
'partner_id': parent_id,
- 'report_logbook_sj_id': report_logbook.id
+ 'report_logbook_sj_id': report_logbook.id,
+ 'note': line.note
}
self.env['report.logbook.sj.line'].create([data])
@@ -69,6 +70,7 @@ class LogbookSJLine(models.TransientModel):
logbook_sj_id = fields.Many2one('logbook.sj', string='Logbook SJ')
partner_id = fields.Many2one('res.partner', string='Customer')
picking_id = fields.Many2one('res.partner', string='Customer')
+ note = fields.Char(string='Note')
@api.onchange('name')
def onchange_name(self):
diff --git a/indoteknik_custom/models/purchase_order_line.py b/indoteknik_custom/models/purchase_order_line.py
index c2e7a4c7..2eeb7d3e 100755
--- a/indoteknik_custom/models/purchase_order_line.py
+++ b/indoteknik_custom/models/purchase_order_line.py
@@ -40,6 +40,50 @@ class PurchaseOrderLine(models.Model):
delete_line = fields.Boolean(string='Delete', default=False, help='centang ini jika anda ingin menghapus line ini')
is_edit_product_qty = fields.Boolean(string='Is Edit Product Qty', compute='_compute_is_edit_product_qty')
+ @api.constrains('price_unit')
+ def constrains_purchase_price(self):
+ for line in self:
+ matches_so = self.env['purchase.order.sales.match'].search([
+ ('purchase_order_id', '=', line.order_id.id),
+ ('product_id', '=', line.product_id.id),
+ ])
+
+ matches_so.sale_line_id.purchase_price = line.price_unit
+
+ @api.constrains('product_qty')
+ def constrains_product_qty(self):
+ for line in self:
+ qty_po = 0
+ matches_so = self.env['purchase.order.sales.match'].search([
+ ('purchase_order_id', '=', line.order_id.id),
+ ('product_id', '=', line.product_id.id),
+ ])
+
+ if not matches_so:
+ continue
+
+ for matches in matches_so:
+ qty_po += matches.qty_po
+
+ if qty_po == line.product_qty:
+ continue
+
+ oldest_date_order = min(matches_so.mapped('sale_id.date_order'))
+ oldest_matches = matches_so.filtered(lambda x: x.sale_id.date_order == oldest_date_order)
+ matches_to_remove = matches_so - oldest_matches
+
+ if matches_to_remove:
+ matches_to_remove.unlink()
+
+ def unlink(self):
+ for line in self:
+ mathces_so = self.env['purchase.order.sales.match'].search([
+ ('purchase_order_id', '=', line.order_id.id),
+ ('product_id', '=', line.product_id.id),
+ ])
+ mathces_so.unlink()
+ return super(PurchaseOrderLine, self).unlink()
+
def _compute_is_edit_product_qty(self):
for line in self:
diff --git a/indoteknik_custom/models/report_logbook_sj.py b/indoteknik_custom/models/report_logbook_sj.py
index f34835ae..093848b5 100644
--- a/indoteknik_custom/models/report_logbook_sj.py
+++ b/indoteknik_custom/models/report_logbook_sj.py
@@ -67,3 +67,4 @@ class ReportLogbookSJLine(models.Model):
sale_id = fields.Many2one('sale.order', string='Sale Order')
report_logbook_sj_id = fields.Many2one('report.logbook.sj', string='Logbook SJ')
not_exist = fields.Boolean(string='Not Exist')
+ note = fields.Char(string='Note')
diff --git a/indoteknik_custom/models/sale_order.py b/indoteknik_custom/models/sale_order.py
index 88d9aec7..1c85914e 100755
--- a/indoteknik_custom/models/sale_order.py
+++ b/indoteknik_custom/models/sale_order.py
@@ -40,8 +40,7 @@ class SaleOrder(models.Model):
domain="['|', ('company_id', '=', False), ('company_id', '=', company_id)]",
help="Dipakai untuk alamat tempel")
real_invoice_id = fields.Many2one(
- 'res.partner', string='Delivery Invoice Address', readonly=True, required=True,
- states={'draft': [('readonly', False)], 'sent': [('readonly', False)], 'sale': [('readonly', False)]},
+ 'res.partner', string='Delivery Invoice Address', required=True,
domain="['|', ('company_id', '=', False), ('company_id', '=', company_id)]",
help="Dipakai untuk alamat tempel")
fee_third_party = fields.Float('Fee Pihak Ketiga')
diff --git a/indoteknik_custom/models/solr/promotion_program_line.py b/indoteknik_custom/models/solr/promotion_program_line.py
index 9cd226fb..36aea1ed 100644
--- a/indoteknik_custom/models/solr/promotion_program_line.py
+++ b/indoteknik_custom/models/solr/promotion_program_line.py
@@ -75,3 +75,8 @@ class PromotionProgramLine(models.Model):
for record in records:
record._create_solr_queue('_sync_to_solr')
record.solr_flag = 1
+
+ def action_sync_to_solr(self):
+ rec_ids = self.env.context.get('active_ids', [])
+ recs = self.search([('id', 'in', rec_ids)])
+ recs._create_solr_queue('_sync_to_solr') \ No newline at end of file
diff --git a/indoteknik_custom/models/voucher.py b/indoteknik_custom/models/voucher.py
index 588e9ac5..66f763e0 100644
--- a/indoteknik_custom/models/voucher.py
+++ b/indoteknik_custom/models/voucher.py
@@ -153,7 +153,7 @@ class Voucher(models.Model):
discount_all = total['all'] * decimal_discount
result['all'] = min(discount_all, self.max_discount_amount) if self.max_discount_amount > 0 else discount_all
else:
- result['all'] = self.discount_amount
+ result['all'] = min(self.discount_amount, total['all'])
return result
@@ -169,7 +169,7 @@ class Voucher(models.Model):
discount_brand = total_brand * decimal_discount
discount_brand = min(discount_brand, line.max_discount_amount) if line.max_discount_amount > 0 else discount_brand
else:
- discount_brand = line.discount_amount
+ discount_brand = min(line.discount_amount, total_brand)
result['brand'][manufacture_id] = round(discount_brand, 2)
result['all'] += discount_brand
diff --git a/indoteknik_custom/views/account_move.xml b/indoteknik_custom/views/account_move.xml
index f505ef9d..1be6d118 100644
--- a/indoteknik_custom/views/account_move.xml
+++ b/indoteknik_custom/views/account_move.xml
@@ -50,9 +50,14 @@
<field name="date_terima_tukar_faktur"/>
<field name="due_extension"/>
<field name="counter"/>
+ <field name="nomor_kwitansi"/>
</field>
<field name="to_check" position="after">
<field name="already_paid"/>
+ <field name="so_shipping_paid_by"/>
+ <field name="so_shipping_covered_by"/>
+ <field name="so_delivery_amt"/>
+ <field name="flag_delivery_amt"/>
</field>
<notebook position="inside">
<page string="Due Extension" attrs="{'invisible': [('move_type', '!=', 'out_invoice')]}">
diff --git a/indoteknik_custom/views/automatic_purchase.xml b/indoteknik_custom/views/automatic_purchase.xml
index 360fdd16..974fbd17 100644
--- a/indoteknik_custom/views/automatic_purchase.xml
+++ b/indoteknik_custom/views/automatic_purchase.xml
@@ -30,7 +30,7 @@
<field name="qty_max"/>
<field name="qty_available"/>
<field name="qty_purchase"/>
- <field name="partner_id"/>
+ <field name="partner_id" required="1"/>
<field name="last_price"/>
<field name="taxes_id"/>
<field name="subtotal"/>
@@ -52,6 +52,8 @@
<field name="partner_id" readonly="1" optional="hide"/>
<field name="partner_invoice_id" readonly="1"/>
<field name="salesperson_id" readonly="1"/>
+ <field name="purchase_price" readonly="1"/>
+ <field name="purchase_tax_id" readonly="1"/>
<field name="product_id" readonly="1"/>
<field name="qty_so" readonly="1"/>
<field name="qty_po" readonly="1"/>
diff --git a/indoteknik_custom/views/cust_commision.xml b/indoteknik_custom/views/cust_commision.xml
index be58a68c..f080bc60 100644
--- a/indoteknik_custom/views/cust_commision.xml
+++ b/indoteknik_custom/views/cust_commision.xml
@@ -12,6 +12,7 @@
<field name="achieve_1st"/>
<field name="achieve_2nd"/>
<field name="commision_type"/>
+ <field name="brand_ids"/>
</tree>
</field>
</record>
@@ -31,6 +32,7 @@
<field name="achieve_1st"/>
<field name="achieve_2nd"/>
<field name="commision_type"/>
+ <field name="brand_ids"/>
</group>
</group>
</sheet>
diff --git a/indoteknik_custom/views/customer_commision.xml b/indoteknik_custom/views/customer_commision.xml
index 600ad192..4b74cd34 100644
--- a/indoteknik_custom/views/customer_commision.xml
+++ b/indoteknik_custom/views/customer_commision.xml
@@ -12,6 +12,7 @@
<field name="commision_percent"/>
<field name="commision_amt" readonly="1"/>
<field name="status" readonly="1"/>
+ <field name="brand_ids" widget="many2many_tags"/>
</tree>
</field>
</record>
@@ -63,6 +64,7 @@
</div>
<field name="date_to"/>
<field name="commision_type"/>
+ <field name="brand_ids" widget="many2many_tags"/>
<field name="notification" readonly="1"/>
<field name="status" readonly="1"/>
<field name="total_dpp"/>
diff --git a/indoteknik_custom/views/ir_sequence.xml b/indoteknik_custom/views/ir_sequence.xml
index d52f55ca..af07ba38 100644
--- a/indoteknik_custom/views/ir_sequence.xml
+++ b/indoteknik_custom/views/ir_sequence.xml
@@ -90,6 +90,15 @@
<field name="number_next">1</field>
<field name="number_increment">1</field>
</record>
-
+
+ <record id="sequence_nomor_kwitansi" model="ir.sequence">
+ <field name="name">Nomor Kwitansi</field>
+ <field name="code">nomor.kwitansi</field>
+ <field name="active">TRUE</field>
+ <field name="prefix">KWT/%(year)s/</field>
+ <field name="padding">5</field>
+ <field name="number_next">1</field>
+ <field name="number_increment">1</field>
+ </record>
</data>
</odoo> \ No newline at end of file
diff --git a/indoteknik_custom/views/logbook_sj.xml b/indoteknik_custom/views/logbook_sj.xml
index 9eb9aa12..0fa65be5 100644
--- a/indoteknik_custom/views/logbook_sj.xml
+++ b/indoteknik_custom/views/logbook_sj.xml
@@ -22,6 +22,7 @@
<field name="carrier_id" readonly="1"/>
<field name="tracking_no" readonly="1"/>
<field name="partner_id" readonly="1"/>
+ <field name="note"/>
</tree>
</field>
</sheet>
diff --git a/indoteknik_custom/views/promotion/promotion_program_line.xml b/indoteknik_custom/views/promotion/promotion_program_line.xml
index 025ea35a..7c8e403d 100644
--- a/indoteknik_custom/views/promotion/promotion_program_line.xml
+++ b/indoteknik_custom/views/promotion/promotion_program_line.xml
@@ -73,6 +73,14 @@
action="promotion_program_line_action"
/>
+ <record id="ir_actions_server_promotion_program_line_sync_to_solr" model="ir.actions.server">
+ <field name="name">Sync to Solr</field>
+ <field name="model_id" ref="indoteknik_custom.model_promotion_program_line"/>
+ <field name="binding_model_id" ref="indoteknik_custom.model_promotion_program_line"/>
+ <field name="state">code</field>
+ <field name="code">model.action_sync_to_solr()</field>
+ </record>
+
<data noupdate="1">
<record id="cron_program_line_solr_flag_solr" model="ir.cron">
<field name="name">Program Line: Solr Flag to Queue</field>
diff --git a/indoteknik_custom/views/report_logbook_sj.xml b/indoteknik_custom/views/report_logbook_sj.xml
index 8221b419..687464f0 100644
--- a/indoteknik_custom/views/report_logbook_sj.xml
+++ b/indoteknik_custom/views/report_logbook_sj.xml
@@ -31,6 +31,7 @@
<field name="picking_id"/>
<field name="sale_id"/>
<field name="not_exist"/>
+ <field name="note"/>
</tree>
</field>
</record>
diff --git a/indoteknik_custom/views/sale_order.xml b/indoteknik_custom/views/sale_order.xml
index c455655b..23905ef7 100755
--- a/indoteknik_custom/views/sale_order.xml
+++ b/indoteknik_custom/views/sale_order.xml
@@ -49,7 +49,6 @@
</field>
<field name="user_id" position="after">
<field name="helper_by_id" readonly="1"/>
- <field name="compute_fullfillment" invisible="1"/>
</field>
<field name="tag_ids" position="after">
<field name="eta_date" readonly="1"/>
@@ -187,9 +186,6 @@
<page string="Matches PO" name="page_matches_po" invisible="1">
<field name="order_sales_match_line" readonly="1"/>
</page>
- <page string="Fullfillment" name="page_sale_order_fullfillment">
- <field name="fullfillment_line" readonly="1"/>
- </page>
</page>
</field>
</record>