summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortrisusilo48 <tri.susilo@altama.co.id>2024-12-05 14:47:42 +0700
committertrisusilo48 <tri.susilo@altama.co.id>2024-12-05 14:47:42 +0700
commit1e9e0c28ee4dc63f1465affac6d98ae213d9f283 (patch)
treee48922d3885f3c1870f24cfad2c708389468d722
parent4d5a0a6e2d997e323f8670172226f613b7673d62 (diff)
parent4eac4d0709ec5d9e03b517a39cb67acbc35e2932 (diff)
Merge branch 'production' of https://bitbucket.org/altafixco/indoteknik-addons into production
-rw-r--r--indoteknik_api/controllers/api_v1/sale_order.py6
-rw-r--r--indoteknik_api/models/product_template.py6
-rw-r--r--indoteknik_api/models/res_users.py6
-rw-r--r--indoteknik_api/models/sale_order.py7
-rwxr-xr-xindoteknik_custom/__manifest__.py2
-rwxr-xr-xindoteknik_custom/models/__init__.py2
-rwxr-xr-xindoteknik_custom/models/product_template.py82
-rw-r--r--indoteknik_custom/models/promotion/sale_order.py11
-rwxr-xr-xindoteknik_custom/models/purchase_order.py34
-rw-r--r--indoteknik_custom/models/purchasing_job.py2
-rw-r--r--indoteknik_custom/models/res_partner.py12
-rwxr-xr-xindoteknik_custom/models/sale_order.py56
-rw-r--r--indoteknik_custom/models/sale_order_line.py2
-rw-r--r--indoteknik_custom/models/stock_picking.py113
-rw-r--r--indoteknik_custom/models/va_multi_approve.py22
-rw-r--r--indoteknik_custom/models/va_multi_reject.py22
-rw-r--r--indoteknik_custom/models/vendor_approval.py103
-rwxr-xr-xindoteknik_custom/security/ir.model.access.csv4
-rw-r--r--indoteknik_custom/views/form_vendor_approval_multi_approve.xml31
-rw-r--r--indoteknik_custom/views/form_vendor_approval_multi_reject.xml31
-rwxr-xr-xindoteknik_custom/views/product_template.xml6
-rwxr-xr-xindoteknik_custom/views/sale_order.xml6
-rw-r--r--indoteknik_custom/views/stock_picking.xml23
-rw-r--r--indoteknik_custom/views/vendor_approval.xml66
24 files changed, 527 insertions, 128 deletions
diff --git a/indoteknik_api/controllers/api_v1/sale_order.py b/indoteknik_api/controllers/api_v1/sale_order.py
index 3e182a2e..8b95ade8 100644
--- a/indoteknik_api/controllers/api_v1/sale_order.py
+++ b/indoteknik_api/controllers/api_v1/sale_order.py
@@ -150,7 +150,8 @@ class SaleOrder(controller.Controller):
def partner_checkout_sale_order_by_id(self, **kw):
params = self.get_request_params(kw, {
'partner_id': ['number'],
- 'id': ['number']
+ 'id': ['number'],
+ 'status': ['boolean']
})
if not params['valid']:
return self.response(code=400, description=params)
@@ -163,6 +164,9 @@ class SaleOrder(controller.Controller):
data = {}
sale_order = request.env['sale.order'].search(domain)
if sale_order:
+ if 'status' in params['value']:
+ sale_order.is_continue_transaction = params['value']['status']
+
if sale_order._requires_approval_margin_leader():
sale_order.approval_status = 'pengajuan2'
elif sale_order._requires_approval_margin_manager():
diff --git a/indoteknik_api/models/product_template.py b/indoteknik_api/models/product_template.py
index 75899624..e46e44d3 100644
--- a/indoteknik_api/models/product_template.py
+++ b/indoteknik_api/models/product_template.py
@@ -7,6 +7,11 @@ class ProductTemplate(models.Model):
def api_single_response(self, product_template, with_detail=''):
product_pricelist_default_discount_id = self.env['ir.config_parameter'].get_param('product.pricelist.default_discount_id')
product_pricelist_default_discount_id = int(product_pricelist_default_discount_id)
+ voucher = self.get_voucher_pastihemat(product_template.x_manufacture.id)
+ newVoucherPastiHemat = {"min_purchase": voucher.min_purchase_amount or 0,
+ "discount_type": voucher.discount_type or '',
+ "discount_amount": voucher.discount_amount or 0,
+ "max_discount": voucher.max_discount_amount or 0,}
data = {
'id': product_template.id,
'image': self.env['ir.attachment'].api_image('product.template', 'image_128', product_template.id),
@@ -18,6 +23,7 @@ class ProductTemplate(models.Model):
'weight': product_template.weight,
'manufacture': self.api_manufacture(product_template),
'categories': self.api_categories(product_template),
+ "newVoucherPastiHemat": newVoucherPastiHemat
}
if with_detail != '':
diff --git a/indoteknik_api/models/res_users.py b/indoteknik_api/models/res_users.py
index 230707cb..52a044dc 100644
--- a/indoteknik_api/models/res_users.py
+++ b/indoteknik_api/models/res_users.py
@@ -14,6 +14,9 @@ class ResUsers(models.Model):
'manager': 2,
'director': 3
}
+ partner_tempo = False
+ if main_partner:
+ partner_tempo = main_partner.get_check_tempo_partner()
data = {
'id': res_user.id,
@@ -32,7 +35,8 @@ class ResUsers(models.Model):
'feature': {
'so_approval': main_partner.use_so_approval,
'only_ready_stock': main_partner.use_only_ready_stock
- }
+ },
+ 'partner_tempo': partner_tempo
}
return data
diff --git a/indoteknik_api/models/sale_order.py b/indoteknik_api/models/sale_order.py
index 54e1fd40..727379c5 100644
--- a/indoteknik_api/models/sale_order.py
+++ b/indoteknik_api/models/sale_order.py
@@ -39,6 +39,8 @@ class SaleOrder(models.Model):
data['status'] = 'cancel'
if sale_order.state in ['draft', 'sent']:
data['status'] = 'draft'
+ if sale_order.is_continue_transaction:
+ data['status'] = 'waiting'
if sale_order.approval_status in ['pengajuan1', 'pengajuan2']:
data['status'] = 'waiting'
if sale_order.state == 'sale':
@@ -85,6 +87,11 @@ class SaleOrder(models.Model):
}
product['quantity'] = line.product_uom_qty
product['available_quantity'] = line.product_available_quantity
+ for data_v2 in sale_order.fulfillment_line_v2:
+ product_v2 = self.env['product.product'].api_single_response(data_v2.product_id)
+ if product['id'] == product_v2['id']:
+ product['so_qty'] = data_v2.so_qty
+ product['reserved_stock_qty'] = data_v2.reserved_stock_qty
data_with_detail['products'].append(product)
for invoice in sale_order.invoice_ids:
if invoice.state == 'posted':
diff --git a/indoteknik_custom/__manifest__.py b/indoteknik_custom/__manifest__.py
index da44ebf3..89f62524 100755
--- a/indoteknik_custom/__manifest__.py
+++ b/indoteknik_custom/__manifest__.py
@@ -146,6 +146,8 @@
'views/vendor_approval.xml',
'views/find_page.xml',
'views/approval_retur_picking.xml',
+ 'views/form_vendor_approval_multi_approve.xml',
+ 'views/form_vendor_approval_multi_reject.xml',
'report/report.xml',
'report/report_banner_banner.xml',
'report/report_banner_banner2.xml',
diff --git a/indoteknik_custom/models/__init__.py b/indoteknik_custom/models/__init__.py
index 4983cc17..ad6d75dd 100755
--- a/indoteknik_custom/models/__init__.py
+++ b/indoteknik_custom/models/__init__.py
@@ -132,3 +132,5 @@ from . import vendor_approval
from . import partner
from . import find_page
from . import approval_retur_picking
+from . import va_multi_approve
+from . import va_multi_reject
diff --git a/indoteknik_custom/models/product_template.py b/indoteknik_custom/models/product_template.py
index 25473ab8..6fb8c7a0 100755
--- a/indoteknik_custom/models/product_template.py
+++ b/indoteknik_custom/models/product_template.py
@@ -1,4 +1,4 @@
-from odoo import fields, models, api
+from odoo import fields, models, api, tools, _
from datetime import datetime, timedelta, date
from odoo.exceptions import UserError
import logging
@@ -61,11 +61,12 @@ class ProductTemplate(models.Model):
sni = fields.Boolean(string='SNI')
tkdn = fields.Boolean(string='TKDN')
short_spesification = fields.Char(string='Short Spesification')
+ merchandise_ok = fields.Boolean(string='Product Promotion')
@api.constrains('name', 'internal_reference', 'x_manufacture')
def required_public_categ_ids(self):
for rec in self:
- if not rec.public_categ_ids:
+ if not rec.public_categ_ids and rec.type == 'product':
raise UserError('Field Categories harus diisi')
def _get_qty_sold(self):
@@ -377,6 +378,7 @@ class ProductProduct(models.Model):
max_qty_reorder = fields.Float(string='Max Qty Reorder', compute='_get_max_qty_reordering_rule')
qty_rpo = fields.Float(string='Qty RPO', compute='_get_qty_rpo')
plafon_qty = fields.Float(string='Max Plafon', compute='_get_plafon_qty_product')
+ merchandise_ok = fields.Boolean(string='Product Promotion')
def _get_clean_website_description(self):
for rec in self:
@@ -386,7 +388,7 @@ class ProductProduct(models.Model):
@api.constrains('name', 'internal_reference', 'x_manufacture')
def required_public_categ_ids(self):
for rec in self:
- if not rec.public_categ_ids:
+ if not rec.public_categ_ids and rec.type == 'product':
raise UserError('Field Categories harus diisi')
@api.constrains('active')
@@ -482,33 +484,38 @@ class ProductProduct(models.Model):
def _get_qty_incoming_bandengan(self):
for product in self:
- qty_incoming = self.env['stock.move'].search([
- ('product_id', '=', product.id),
- ('location_dest_id', 'in', [57, 83]),
- ('state', 'not in', ['done', 'cancel'])
- ])
- qty = sum(qty_incoming.mapped('product_uom_qty'))
+ qty = self.env['v.move.outstanding'].read_group(
+ domain=[
+ ('product_id', '=', product.id),
+ ('location_dest_id', 'in', [57, 83]),
+ ],
+ fields=['qty_need'],
+ groupby=[]
+ )[0].get('qty_need', 0.0)
product.qty_incoming_bandengan = qty
def _get_qty_incoming_bandengan_with_exclude(self):
for product in self:
- qty_incoming = self.env['stock.move'].search([
- ('product_id', '=', product.id),
- ('location_dest_id', 'in', [57, 83]),
- ('state', 'not in', ['done', 'cancel'])
- ])
- qty = sum(qty_incoming.mapped('product_uom_qty'))
+ qty = self.env['v.move.outstanding'].read_group(
+ domain=[
+ ('product_id', '=', product.id),
+ ('location_dest_id', 'in', [57, 83]),
+ ],
+ fields=['qty_need'],
+ groupby=[]
+ )[0].get('qty_need', 0.0)
product.qty_incoming_bandengan = qty
def _get_qty_outgoing_bandengan(self):
for product in self:
- qty_incoming = self.env['stock.move'].search([
- ('product_id', '=', product.id),
- ('location_dest_id', '=', 5),
- ('location_id', 'in', [57, 83]),
- ('state', 'not in', ['done', 'cancel'])
- ])
- qty = sum(qty_incoming.mapped('product_uom_qty'))
+ qty = self.env['v.move.outstanding'].read_group(
+ domain=[
+ ('product_id', '=', product.id),
+ ('location_id', 'in', [57, 83]),
+ ],
+ fields=['qty_need'],
+ groupby=[]
+ )[0].get('qty_need', 0.0)
product.qty_outgoing_bandengan = qty
def _get_qty_onhand_bandengan(self):
@@ -598,3 +605,34 @@ class ProductProduct(models.Model):
('end_date', '>=', current_time)
], limit=1)
return pricelist
+
+
+class OutstandingMove(models.Model):
+ _name = 'v.move.outstanding'
+ _auto = False
+ _rec_name = 'id'
+
+ id = fields.Integer(string='ID')
+ product_id = fields.Many2one('product.product', string='Product')
+ reference = fields.Char(string='Reference', help='Nomor Dokumen terkait')
+ qty_need = fields.Float(string='Qty Need', help='Qty yang akan outgoing / incoming')
+ location_id = fields.Many2one('stock.location', string='Location', help='Lokasi asal')
+ location_dest_id = fields.Many2one('stock.location', string='Location To', help='Lokasi tujuan')
+
+ def init(self):
+ # where clause 'state in' follow the origin of outgoing and incoming odoo
+ tools.drop_view_if_exists(self.env.cr, self._table)
+ self.env.cr.execute("""
+ CREATE OR REPLACE VIEW %s AS
+ select sm.id, sm.reference, sm.product_id,
+ sm.product_uom_qty as qty_need,
+ sm.location_id, sm.location_dest_id
+ from stock_move sm
+ where 1=1
+ and sm.state in(
+ 'waiting',
+ 'confirmed',
+ 'assigned',
+ 'partially_available'
+ )
+ """ % self._table)
diff --git a/indoteknik_custom/models/promotion/sale_order.py b/indoteknik_custom/models/promotion/sale_order.py
index be820c6f..1c31d060 100644
--- a/indoteknik_custom/models/promotion/sale_order.py
+++ b/indoteknik_custom/models/promotion/sale_order.py
@@ -10,11 +10,12 @@ class SaleOrder(models.Model):
for promotion in promotions:
program_line = self.env['promotion.program.line'].browse(promotion['program_line_id'])
for free_product in program_line.free_product_ids:
- self.env['sale.order.line'].create({
- 'order_id': self.id,
- 'name': "Free Product " + free_product.product_id.display_name,
- 'display_type': 'line_note'
- })
+ if free_product.product_id.merchandise_ok:
+ self.env['sale.order.line'].create({
+ 'order_id': self.id,
+ 'name': f"Free Product {free_product.product_id.display_name} Quantity ({free_product.qty})",
+ 'display_type': 'line_note'
+ })
def apply_promotion_program(self):
userdata = {
diff --git a/indoteknik_custom/models/purchase_order.py b/indoteknik_custom/models/purchase_order.py
index 3397616d..9388ae4c 100755
--- a/indoteknik_custom/models/purchase_order.py
+++ b/indoteknik_custom/models/purchase_order.py
@@ -595,10 +595,19 @@ class PurchaseOrder(models.Model):
if line.product_uom_qty > line.product_id.plafon_qty + line.product_uom_qty and not self.env.user.has_group('indoteknik_custom.group_role_merchandiser'):
raise UserError('Product '+line.product_id.name+' melebihi plafon, harus Approval MD')
+ def check_different_vendor_so_po(self):
+ vendor_po = self.partner_id.id
+ for line in self.order_line:
+ if not line.so_line_id:
+ continue
+ if line.so_line_id.vendor_id.id != vendor_po and not self.env.user.has_group('indoteknik_custom.group_role_merchandiser'):
+ raise UserError("Produk "+line.product_id.name+" memiliki vendor berbeda dengan SO (Vendor PO: "+str(self.partner_id.name)+", Vendor SO: "+str(line.so_line_id.vendor_id.name)+")")
+
def button_confirm(self):
res = super(PurchaseOrder, self).button_confirm()
current_time = datetime.now()
self.check_ppn_mix()
+ self.check_different_vendor_so_po()
# self.check_data_vendor()
if self.amount_untaxed >= 50000000 and not self.env.user.has_group('indoteknik_custom.group_role_merchandiser'):
@@ -736,12 +745,12 @@ class PurchaseOrder(models.Model):
template.send_mail(self.id, force_send=True)
def po_approve(self):
- # if self.amount_untaxed >= 50000000 and not self.env.user.has_group('indoteknik_custom.group_role_merchandiser'):
- # raise UserError("Hanya Merchandiser yang bisa approve")
greater_than_plafon, message = self._get_msg_plafon_qty()
+ different_vendor_message = self.check_different_vendor_so() # Panggil fungsi check_different_vendor_so
+
if self.env.user.is_leader or self.env.user.has_group('indoteknik_custom.group_role_merchandiser'):
raise UserError("Bisa langsung Confirm")
- elif self.total_percent_margin == self.total_so_percent_margin and self.matches_so and not greater_than_plafon:
+ elif self.total_percent_margin == self.total_so_percent_margin and self.matches_so and not greater_than_plafon and not different_vendor_message:
raise UserError("Bisa langsung Confirm")
else:
reason = ''
@@ -757,13 +766,30 @@ class PurchaseOrder(models.Model):
# Check Plafon Qty and Get Message every Line Product
if greater_than_plafon:
reason += message
+ # Check for Different Vendor Message
+ if different_vendor_message:
+ reason += different_vendor_message
+
# Post a highlighted message to lognote
self.message_post(
body=f"<div style='background-color: #fdf2e9; border: 1px solid #f5c6cb; padding: 10px;'>"
- f"<b>Note (Pinned):</b><br>{reason}</div>",
+ f"<b>Note (Pinned):</b><br>{reason}</div>",
subtype_id=self.env.ref("mail.mt_note").id
)
+
+ def check_different_vendor_so(self):
+ vendor_po = self.partner_id.id
+ message = ''
+ for line in self.order_line:
+ if not line.so_line_id:
+ continue
+ if line.so_line_id.vendor_id.id != vendor_po:
+ product_code = line.product_id.display_name or 'Unknown'
+ message += (f"Produk {product_code} memiliki vendor berbeda dengan SO "
+ f"(Vendor PO: {self.partner_id.name}, Vendor SO: {line.so_line_id.vendor_id.name}), ")
+ return message if message else None
+
def _get_msg_plafon_qty(self):
message = ''
greater_than_plafon = False
diff --git a/indoteknik_custom/models/purchasing_job.py b/indoteknik_custom/models/purchasing_job.py
index bf5ed8c4..4efb0cd4 100644
--- a/indoteknik_custom/models/purchasing_job.py
+++ b/indoteknik_custom/models/purchasing_job.py
@@ -57,7 +57,7 @@ class PurchasingJob(models.Model):
max(pjs.status_apo::text) AS status_apo,
max(pjs.note::text) AS note,
CASE
- WHEN sub.vendor_id = 5571 THEN 27
+ WHEN pmp.brand IN ('Tekiro', 'RYU', 'Rexco') THEN 27
WHEN sub.vendor_id = 9688 THEN 397
WHEN sub.vendor_id = 35475 THEN 397
WHEN sub.vendor_id = 29712 THEN 397
diff --git a/indoteknik_custom/models/res_partner.py b/indoteknik_custom/models/res_partner.py
index 4297012c..da4a6cb6 100644
--- a/indoteknik_custom/models/res_partner.py
+++ b/indoteknik_custom/models/res_partner.py
@@ -1,7 +1,7 @@
from odoo import models, fields, api
from odoo.exceptions import UserError, ValidationError
from datetime import datetime
-
+from odoo.http import request
class GroupPartner(models.Model):
_name = 'group.partner'
@@ -244,6 +244,14 @@ class ResPartner(models.Model):
def _onchange_customer_type(self):
if self.customer_type == 'nonpkp':
self.npwp = '00.000.000.0-000.000'
-
+ def get_check_tempo_partner(self):
+ self.ensure_one()
+
+ partner = self.parent_id or self
+
+ if not partner.property_payment_term_id or 'Tempo' not in partner.property_payment_term_id.name:
+ return False
+ else:
+ return True
diff --git a/indoteknik_custom/models/sale_order.py b/indoteknik_custom/models/sale_order.py
index 5e868edd..7fc6d96a 100755
--- a/indoteknik_custom/models/sale_order.py
+++ b/indoteknik_custom/models/sale_order.py
@@ -79,7 +79,7 @@ class SaleOrder(models.Model):
payment_link_midtrans = fields.Char(string='Payment Link', help='Url payment yg digenerate oleh midtrans, harap diserahkan ke customer agar dapat dilakukan pembayaran secara mandiri')
payment_qr_code = fields.Binary("Payment QR Code")
due_id = fields.Many2one('due.extension', string="Due Extension", readonly=True, tracking=True)
- vendor_approval_id = fields.Many2one('vendor.approval', string="Vendor Approval", readonly=True, tracking=True, copy=False)
+ vendor_approval_id = fields.Many2many('vendor.approval', string="Vendor Approval", readonly=True, tracking=True, copy=False)
customer_type = fields.Selection([
('pkp', 'PKP'),
('nonpkp', 'Non PKP')
@@ -99,6 +99,7 @@ class SaleOrder(models.Model):
helper_by_id = fields.Many2one('res.users', 'Helper By')
eta_date = fields.Datetime(string='ETA Date', copy=False, compute='_compute_eta_date')
flash_sale = fields.Boolean(string='Flash Sale', help='Data dari web')
+ is_continue_transaction = fields.Boolean(string='Button Transaction', help='Data dari web')
web_approval = fields.Selection([
('company', 'Company'),
('cust_manager', 'Customer Manager'),
@@ -144,6 +145,14 @@ class SaleOrder(models.Model):
('NP', 'Non Pareto')
])
+ @api.onchange('payment_status')
+ def _is_continue_transaction(self):
+ if not self.is_continue_transaction:
+ if self.payment_status == 'settlement':
+ self.is_continue_transaction = True
+ else:
+ self.is_continue_transaction = False
+
def _compute_total_weight(self):
total_weight = 0
missing_weight_products = []
@@ -882,29 +891,26 @@ class SaleOrder(models.Model):
}).send()
def validate_different_vendor(self):
- if self.vendor_approval_id and self.vendor_approval_id.state == 'draft':
- raise UserError('SO ini sedang dalam review Vendor Approval')
-
- if self.vendor_approval_id and self.vendor_approval_id.state == 'cancel':
- raise UserError('Vendor Approval SO ini Di Reject')
-
- if self.vendor_approval_id and self.vendor_approval_id.state == 'done':
+ if self.vendor_approval_id.filtered(lambda v: v.state == 'draft'):
+ draft_names = ", ".join(self.vendor_approval_id.filtered(lambda v: v.state == 'draft').mapped('number'))
+ raise UserError(f"SO ini sedang dalam review Vendor Approval: {draft_names}")
+
+ if self.vendor_approval_id and all(v.state != 'draft' for v in self.vendor_approval_id):
return False
- different_vendor = self.order_line.filtered(lambda l: l.vendor_id and l.vendor_md_id and l.vendor_id.id != l.vendor_md_id.id)
+ different_vendor = self.order_line.filtered(
+ lambda l: l.vendor_id and l.vendor_md_id and l.vendor_id.id != l.vendor_md_id.id
+ )
+
if different_vendor:
- vendor_approval = self.env['vendor.approval'].create({
- 'order_id': self.id,
- 'create_date_so': self.create_date,
- 'partner_id': self.partner_id.id,
- 'state': 'draft',
- })
-
- self.vendor_approval_id = vendor_approval.id
-
+ vendor_approvals = []
for line in different_vendor:
- self.env['vendor.approval.line'].create({
- 'vendor_approval_id': vendor_approval.id,
+ vendor_approval = self.env['vendor.approval'].create({
+ 'order_id': self.id,
+ 'order_line_id': line.id,
+ 'create_date_so': self.create_date,
+ 'partner_id': self.partner_id.id,
+ 'state': 'draft',
'product_id': line.product_id.id,
'product_uom_qty': line.product_uom_qty,
'vendor_id': line.vendor_id.id,
@@ -916,9 +922,15 @@ class SaleOrder(models.Model):
'margin_after': line.item_percent_margin,
'purchase_tax_id': line.purchase_tax_id.id,
'sales_tax_id': line.tax_id[0].id if line.tax_id else False,
- 'percent_margin_difference': (line.price_unit - line.purchase_price_md) / line.purchase_price_md if line.purchase_price_md else False,
+ 'percent_margin_difference': (
+ (line.price_unit - line.purchase_price_md) / line.purchase_price_md
+ if line.purchase_price_md else False
+ ),
})
-
+
+ vendor_approvals.append(vendor_approval.id)
+
+ self.vendor_approval_id = [(4, vid) for vid in vendor_approvals]
return True
else:
return False
diff --git a/indoteknik_custom/models/sale_order_line.py b/indoteknik_custom/models/sale_order_line.py
index 04fafa69..a31ff569 100644
--- a/indoteknik_custom/models/sale_order_line.py
+++ b/indoteknik_custom/models/sale_order_line.py
@@ -33,7 +33,7 @@ class SaleOrderLine(models.Model):
qty_reserved = fields.Float(string='Qty Reserved', compute='_compute_qty_reserved')
product_available_quantity = fields.Float(string='Qty pickup by user',)
reserved_from = fields.Char(string='Reserved From', copy=False)
- item_percent_margin_without_deduction = fields.Float('%Margin', compute='_compute_item_margin_without_deduction')
+ item_percent_margin_without_deduction = fields.Float('Margin Without Deduction', compute='_compute_item_margin_without_deduction')
weight = fields.Float(string='Weight')
md_vendor_id = fields.Many2one('res.partner', string='MD Vendor', readonly=True)
margin_md = fields.Float(string='Margin MD')
diff --git a/indoteknik_custom/models/stock_picking.py b/indoteknik_custom/models/stock_picking.py
index 17dd5766..931da588 100644
--- a/indoteknik_custom/models/stock_picking.py
+++ b/indoteknik_custom/models/stock_picking.py
@@ -1,9 +1,11 @@
from odoo import fields, models, api, _
from odoo.exceptions import AccessError, UserError, ValidationError
from odoo.tools.float_utils import float_is_zero
-from datetime import datetime
+from datetime import timedelta
from itertools import groupby
-import pytz, datetime, requests, json
+import pytz, requests, json, requests
+from dateutil import parser
+import datetime
class StockPicking(models.Model):
@@ -113,6 +115,113 @@ class StockPicking(models.Model):
], string='Status Reserve', readonly=True, tracking=True, help="The current state of the stock picking.")
notee = fields.Text(string="Note")
+ # Envio Tracking Section
+ envio_id = fields.Char(string="Envio ID", readonly=True)
+ envio_code = fields.Char(string="Envio Code", readonly=True)
+ envio_ref_code = fields.Char(string="Envio Reference Code", readonly=True)
+ envio_eta_at = fields.Char(string="Estimated Time of Arrival (ETA)", readonly=True)
+ envio_ata_at = fields.Char(string="Actual Time of Arrival (ATA)", readonly=True)
+ envio_etd_at = fields.Char(string="Estimated Time of Departure (ETD)", readonly=True)
+ envio_atd_at = fields.Char(string="Actual Time of Departure (ATD)", readonly=True)
+ envio_received_by = fields.Char(string="Received By", readonly=True)
+ envio_status = fields.Char(string="Status", readonly=True)
+ envio_cod_value = fields.Float(string="COD Value", readonly=True)
+ envio_cod_status = fields.Char(string="COD Status", readonly=True)
+ envio_logs = fields.Text(string="Logs", readonly=True)
+ envio_latest_message = fields.Text(string="Latest Log Message", readonly=True)
+ envio_latest_recorded_at = fields.Char(string="Log Recorded At", readonly=True)
+ envio_latest_latitude = fields.Float(string="Log Latitude", readonly=True)
+ envio_latest_longitude = fields.Float(string="Log Longitude", readonly=True)
+ tracking_by = fields.Many2one('res.users', string='Tracking By', readonly=True, tracking=True)
+
+ def _convert_to_wib(self, date_str):
+ """
+ Mengonversi string waktu ISO 8601 ke format waktu Indonesia (WIB)
+ """
+ if not date_str:
+ return False
+ try:
+ utc_time = datetime.strptime(date_str, '%Y-%m-%dT%H:%M:%SZ')
+ wib_time = utc_time + timedelta(hours=7)
+ return wib_time.strftime('%d-%m-%Y %H:%M:%S')
+ except ValueError:
+ raise UserError(f"Format waktu tidak sesuai: {date_str}")
+
+ def _convert_to_datetime(self, date_str):
+ """Mengonversi string waktu dari API ke datetime."""
+ if not date_str:
+ return False
+ try:
+ # Format waktu dengan milidetik
+ return datetime.strptime(date_str, '%Y-%m-%dT%H:%M:%S.%fZ')
+ except ValueError:
+ try:
+ # Format waktu tanpa milidetik
+ return datetime.strptime(date_str, '%Y-%m-%dT%H:%M:%SZ')
+ except ValueError:
+ raise UserError(f"Format waktu tidak sesuai: {date_str}")
+
+ def track_envio_shipment(self):
+ pickings = self.env['stock.picking'].search([
+ ('picking_type_code', '=', 'outgoing'),
+ ('state', '=', 'done'),
+ ('carrier_id', '=', 151)
+ ])
+ for picking in self:
+ if not picking.name:
+ raise UserError("Name pada stock.picking tidak ditemukan.")
+
+ # API URL dan headers
+ url = f"https://api.envio.co.id/v1/tracking/distribution?code={picking.name}"
+ headers = {
+ 'Authorization': 'Bearer JZ0Seh6qpYJAC3CJHdhF7sPqv8B/uSSfZe1VX5BL?vPYdo',
+ 'Content-Type': 'application/json',
+ }
+
+ try:
+ # Request ke API
+ response = requests.get(url, headers=headers, timeout=10)
+ response.raise_for_status() # Raise error jika status code bukan 200
+ response_data = response.json()
+
+ # Validasi jika respons tidak sesuai format yang diharapkan
+ if not response_data or "data" not in response_data:
+ raise UserError("Respons API tidak sesuai format yang diharapkan.")
+
+ data = response_data.get("data")
+ if not data:
+ continue
+
+ # Menyimpan data ke field masing-masing
+ picking.envio_id = data.get("id")
+ picking.envio_code = data.get("code")
+ picking.envio_ref_code = data.get("ref_code")
+ picking.envio_eta_at = self._convert_to_datetime(data.get("eta_at"))
+ picking.envio_ata_at = self._convert_to_datetime(data.get("ata_at"))
+ picking.envio_etd_at = self._convert_to_datetime(data.get("etd_at"))
+ picking.envio_atd_at = self._convert_to_datetime(data.get("atd_at"))
+ picking.envio_received_by = data.get("received_by")
+ picking.envio_status = data.get("status")
+ picking.envio_cod_value = data.get("cod_value", 0.0)
+ picking.envio_cod_status = data.get("cod_status")
+
+ # Menyimpan log terbaru
+ logs = data.get("logs", [])
+ if logs and isinstance(logs, list) and logs[0]:
+ latest_log = logs[0]
+ picking.envio_latest_message = latest_log.get("message", "Log kosong.")
+ picking.envio_latest_recorded_at = self._convert_to_datetime(latest_log.get("recorded_at"))
+ picking.envio_latest_latitude = latest_log.get("latitude", 0.0)
+ picking.envio_latest_longitude = latest_log.get("longitude", 0.0)
+
+ picking.tracking_by = self.env.user.id
+ ata_at_str = data.get("ata_at")
+ picking.driver_arrival_date = self._convert_to_datetime(ata_at_str) if ata_at_str else False
+ except requests.exceptions.RequestException as e:
+ raise UserError(f"Terjadi kesalahan saat menghubungi API Envio: {str(e)}")
+ except Exception as e:
+ raise UserError(f"Kesalahan tidak terduga: {str(e)}")
+
def action_send_to_biteship(self):
url = "https://api.biteship.com/v1/orders"
api_key = "biteship_test.eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiSW5kb3Rla25payIsInVzZXJJZCI6IjY3MTViYTJkYzVkMjdkMDAxMjRjODk2MiIsImlhdCI6MTcyOTQ5ODAwMX0.L6C73couP4-cgVEfhKI2g7eMCMo3YOFSRZhS-KSuHNA"
diff --git a/indoteknik_custom/models/va_multi_approve.py b/indoteknik_custom/models/va_multi_approve.py
new file mode 100644
index 00000000..028358c2
--- /dev/null
+++ b/indoteknik_custom/models/va_multi_approve.py
@@ -0,0 +1,22 @@
+from odoo import models, fields
+import logging
+
+_logger = logging.getLogger(__name__)
+
+
+class VaMultiApprove(models.TransientModel):
+ _name = 'va.multi.approve'
+
+ def save_multi_approve_va(self):
+ va_ids = self._context['va_ids']
+ vendor_approval = self.env['vendor.approval'].browse(va_ids)
+ vendor_approval.action_approve()
+ return {
+ 'type': 'ir.actions.client',
+ 'tag': 'display_notification',
+ 'params': {
+ 'title': 'Notification',
+ 'message': 'Berhasil Di Approve',
+ 'next': {'type': 'ir.actions.act_window_close'},
+ }
+ } \ No newline at end of file
diff --git a/indoteknik_custom/models/va_multi_reject.py b/indoteknik_custom/models/va_multi_reject.py
new file mode 100644
index 00000000..c05581bf
--- /dev/null
+++ b/indoteknik_custom/models/va_multi_reject.py
@@ -0,0 +1,22 @@
+from odoo import models, fields
+import logging
+
+_logger = logging.getLogger(__name__)
+
+
+class VaMultiReject(models.TransientModel):
+ _name = 'va.multi.reject'
+
+ def save_multi_reject_va(self):
+ va_ids = self._context['va_ids']
+ vendor_approval = self.env['vendor.approval'].browse(va_ids)
+ vendor_approval.action_reject()
+ return {
+ 'type': 'ir.actions.client',
+ 'tag': 'display_notification',
+ 'params': {
+ 'title': 'Notification',
+ 'message': 'Berhasil Di Reject',
+ 'next': {'type': 'ir.actions.act_window_close'},
+ }
+ } \ No newline at end of file
diff --git a/indoteknik_custom/models/vendor_approval.py b/indoteknik_custom/models/vendor_approval.py
index 56b81a37..01d2e6a2 100644
--- a/indoteknik_custom/models/vendor_approval.py
+++ b/indoteknik_custom/models/vendor_approval.py
@@ -13,61 +13,90 @@ class VendorApproval(models.Model):
number = fields.Char(string='Document No', index=True, copy=False, readonly=True, tracking=True)
partner_id = fields.Many2one('res.partner', string="Customer", readonly=True)
+ order_line_id = fields.Many2one('sale.order.line', string="SO Line", readonly=True)
order_id = fields.Many2one('sale.order', string="SO", readonly=True)
- vendor_approval_line = fields.One2many('vendor.approval.line', 'vendor_approval_id', string='Vendor Approval Lines', auto_join=True)
state = fields.Selection([('draft', 'Draft'), ('done', 'Done'), ('cancel', 'Reject')], string='State', tracking=True)
create_date_so = fields.Datetime(string='Create Date SO', readonly=True)
+ product_id = fields.Many2one('product.product', string='Product')
+ product_uom_qty = fields.Float(string='Quantity')
+ vendor_id = fields.Many2one('res.partner', string='Vendor')
+ vendor_md_id = fields.Many2one('res.partner', string='Vendor MD')
+ sales_price = fields.Float(string='Sales Price')
+ margin_before = fields.Float(string='Margin Before')
+ margin_after = fields.Float(string='Margin After')
+ purchase_price = fields.Float(string='Purchase Price')
+ purchase_price_md= fields.Float(string='Purchase Price MD')
+ purchase_tax_id = fields.Many2one('account.tax', string='Purchase Tax', domain=['|', ('active', '=', False), ('active', '=', True)])
+ sales_tax_id = fields.Many2one('account.tax', string='Sales Tax', domain=['|', ('active', '=', False), ('active', '=', True)])
+ percent_margin_difference = fields.Float(string='Percent Margin Difference')
@api.model
def create(self, vals):
vals['number'] = self.env['ir.sequence'].next_by_code('vendor.approval') or '0'
result = super(VendorApproval, self).create(vals)
return result
+
+ def check_state_so(self):
+ for rec in self:
+ if rec.order_id.state != 'draft':
+ raise UserError(f"SO {rec.order_id.name} sudah tidak bisa diubah")
+
def action_approve(self):
- if not self.env.user.has_group('indoteknik_custom.group_role_merchandiser'):
- raise UserError('Hanya Merchandiser yang bisa approve')
-
- self.state = 'done'
- self.order_id.vendor_approval = True
- message = "Vendor Approval approved by %s" % (self.env.user.name)
- self.order_id.message_post(body=message)
- if not self.order_id.due_id and self.order_id.state == 'draft':
- self.order_id.action_confirm()
+ for rec in self:
+ self.check_state_so()
+ if not self.env.user.has_group('indoteknik_custom.group_role_merchandiser'):
+ raise UserError('Hanya Merchandiser yang bisa approve')
+
+ # Set state menjadi 'done'
+ rec.state = 'done'
+ rec.order_id.vendor_approval = True
+ message = f"Vendor Approval approved by {self.env.user.name}"
+ rec.order_id.message_post(body=message)
+
+ # Cek semua vendor.approval dengan order_id yang sama
+ related_approvals = self.env['vendor.approval'].search([('order_id', '=', rec.order_id.id)])
+ if all(approval.state != 'draft' for approval in related_approvals):
+ # Jalankan action_confirm hanya jika semua state bukan draft
+ if not rec.order_id.due_id and rec.order_id.state == 'draft':
+ rec.order_id.action_confirm()
+
def action_reject(self):
- if not self.env.user.has_group('indoteknik_custom.group_role_merchandiser'):
- raise UserError('Hanya Merchandiser yang bisa cancel')
-
- self.state = 'cancel'
+ for rec in self:
+ self.check_state_so()
+ if not self.env.user.has_group('indoteknik_custom.group_role_merchandiser'):
+ raise UserError('Hanya Merchandiser yang bisa cancel')
+
+ rec.state = 'cancel'
+
+ rec.order_line_id.vendor_id = rec.vendor_md_id.id
+ rec.order_line_id.purchase_price = rec.purchase_price_md
- message = "Vendor Approval rejected by %s" % (self.env.user.name)
- self.order_id.message_post(body=message)
+ message = "Vendor Approval rejected by %s" % (self.env.user.name)
+ self.order_id.message_post(body=message)
+
+ related_approvals = self.env['vendor.approval'].search([('order_id', '=', rec.order_id.id)])
+ if all(approval.state != 'draft' for approval in related_approvals):
+ # Jalankan action_confirm hanya jika semua state bukan draft
+ if not rec.order_id.due_id and rec.order_id.state == 'draft':
+ rec.order_id.action_confirm()
def unlink(self):
res = super(VendorApproval, self).unlink()
if not self._name == 'vendor.approval':
raise UserError('Vendor Approval tidak bisa didelete')
return res
-
-
-class VendorApprovalLine(models.Model):
- _name = 'vendor.approval.line'
- _description = 'Vendor Approval Line'
- _order = 'vendor_approval_id, id'
-
- vendor_approval_id = fields.Many2one('vendor.approval', string='Vendor Approval Ref', required=True, ondelete='cascade', index=True, copy=False)
- product_id = fields.Many2one('product.product', string='Product')
- product_uom_qty = fields.Float(string='Quantity')
- vendor_id = fields.Many2one('res.partner', string='Vendor')
- vendor_md_id = fields.Many2one('res.partner', string='Vendor MD')
- sales_price = fields.Float(string='Sales Price')
- margin_before = fields.Float(string='Margin Before')
- margin_after = fields.Float(string='Margin After')
- purchase_price = fields.Float(string='Purchase Price')
- purchase_price_md= fields.Float(string='Purchase Price MD')
- purchase_tax_id = fields.Many2one('account.tax', string='Purchase Tax', domain=['|', ('active', '=', False), ('active', '=', True)])
- sales_tax_id = fields.Many2one('account.tax', string='Sales Tax', domain=['|', ('active', '=', False), ('active', '=', True)])
- percent_margin_difference = fields.Float(string='Percent Margin Difference')
-
+ def open_form_multi_approve(self):
+ action = self.env['ir.actions.act_window']._for_xml_id('indoteknik_custom.action_va_multi_approve')
+ action['context'] = {
+ 'va_ids': [x.id for x in self]
+ }
+ return action
+ def open_form_multi_reject(self):
+ action = self.env['ir.actions.act_window']._for_xml_id('indoteknik_custom.action_va_multi_reject')
+ action['context'] = {
+ 'va_ids': [x.id for x in self]
+ }
+ return action \ No newline at end of file
diff --git a/indoteknik_custom/security/ir.model.access.csv b/indoteknik_custom/security/ir.model.access.csv
index e817a28d..2375df9d 100755
--- a/indoteknik_custom/security/ir.model.access.csv
+++ b/indoteknik_custom/security/ir.model.access.csv
@@ -139,10 +139,12 @@ access_account_tax,access.account.tax,model_account_tax,,1,1,1,1
access_approval_unreserve,access.approval.unreserve,model_approval_unreserve,,1,1,1,1
access_approval_unreserve_line,access.approval.unreserve.line,model_approval_unreserve_line,,1,1,1,1
access_vendor_approval,access.vendor.approval,model_vendor_approval,,1,1,1,1
-access_vendor_approval_line,access.vendor.approval.line,model_vendor_approval_line,,1,1,1,1
access_vit_kota,access.vit.kota,model_vit_kota,,1,1,1,1
access_v_brand_product_category,access.v.brand.product.category,model_v_brand_product_category,,1,1,1,1
access_web_find_page,access.web.find.page,model_web_find_page,,1,1,1,1
access_v_requisition_match_po,access.v.requisition.match.po,model_v_requisition_match_po,,1,1,1,1
access_approval_retur_picking,access.approval.retur.picking,model_approval_retur_picking,,1,1,1,1
access_sales_order_fulfillment_v2,access.sales.order.fulfillment.v2,model_sales_order_fulfillment_v2,,1,1,1,1
+access_v_move_outstanding,access.v.move.outstanding,model_v_move_outstanding,,1,1,1,1
+access_va_multi_approve,access.va.multi.approve,model_va_multi_approve,,1,1,1,1
+access_va_multi_reject,access.va.multi.reject,model_va_multi_reject,,1,1,1,1
diff --git a/indoteknik_custom/views/form_vendor_approval_multi_approve.xml b/indoteknik_custom/views/form_vendor_approval_multi_approve.xml
new file mode 100644
index 00000000..d9be107e
--- /dev/null
+++ b/indoteknik_custom/views/form_vendor_approval_multi_approve.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<odoo>
+ <data>
+ <record id="view_va_multi_approve_form" model="ir.ui.view">
+ <field name="name">VA Multi Approve</field>
+ <field name="model">va.multi.approve</field>
+ <field name="arch" type="xml">
+ <form>
+ <sheet>
+ <group>
+ <span>Apakah Anda Yakin Ingin Approve Vendor Approval?</span>
+ </group>
+ </sheet>
+ <footer>
+ <button name="save_multi_approve_va" string="Update" type="object" default_focus="1" class="oe_highlight"/>
+ <button string="Cancel" class="btn btn-secondary" special="cancel" />
+ </footer>
+ </form>
+ </field>
+ </record>
+
+ <record id="action_va_multi_approve" model="ir.actions.act_window">
+ <field name="name">VA Multi Approve</field>
+ <field name="res_model">va.multi.approve</field>
+ <field name="type">ir.actions.act_window</field>
+ <field name="view_mode">form</field>
+ <field name="view_id" ref="view_va_multi_approve_form"/>
+ <field name="target">new</field>
+ </record>
+ </data>
+</odoo> \ No newline at end of file
diff --git a/indoteknik_custom/views/form_vendor_approval_multi_reject.xml b/indoteknik_custom/views/form_vendor_approval_multi_reject.xml
new file mode 100644
index 00000000..666de261
--- /dev/null
+++ b/indoteknik_custom/views/form_vendor_approval_multi_reject.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<odoo>
+ <data>
+ <record id="view_va_multi_reject_form" model="ir.ui.view">
+ <field name="name">VA Multi Reject</field>
+ <field name="model">va.multi.reject</field>
+ <field name="arch" type="xml">
+ <form>
+ <sheet>
+ <group>
+ <span>Apakah Anda Yakin Ingin Reject Vendor Approval?</span>
+ </group>
+ </sheet>
+ <footer>
+ <button name="save_multi_reject_va" string="Update" type="object" default_focus="1" class="oe_highlight"/>
+ <button string="Cancel" class="btn btn-secondary" special="cancel" />
+ </footer>
+ </form>
+ </field>
+ </record>
+
+ <record id="action_va_multi_reject" model="ir.actions.act_window">
+ <field name="name">VA Multi Reject</field>
+ <field name="res_model">va.multi.reject</field>
+ <field name="type">ir.actions.act_window</field>
+ <field name="view_mode">form</field>
+ <field name="view_id" ref="view_va_multi_reject_form"/>
+ <field name="target">new</field>
+ </record>
+ </data>
+</odoo> \ No newline at end of file
diff --git a/indoteknik_custom/views/product_template.xml b/indoteknik_custom/views/product_template.xml
index 5a509ebd..b6599137 100755
--- a/indoteknik_custom/views/product_template.xml
+++ b/indoteknik_custom/views/product_template.xml
@@ -24,6 +24,12 @@
<field name="public_categ_ids" position="attributes">
<attribute name="required">0</attribute>
</field>
+ <div name="options" position="inside">
+ <div>
+ <field name="merchandise_ok"/>
+ <label for="merchandise_ok"/>
+ </div>
+ </div>
<field name="public_categ_ids" position="attributes">
<attribute name="options">{'no_create': True}</attribute>
</field>
diff --git a/indoteknik_custom/views/sale_order.xml b/indoteknik_custom/views/sale_order.xml
index 3a3b1c81..703b4d49 100755
--- a/indoteknik_custom/views/sale_order.xml
+++ b/indoteknik_custom/views/sale_order.xml
@@ -82,7 +82,7 @@
<field name="email" required="1"/>
<field name="unreserve_id"/>
<field name="due_id" readonly="1"/>
- <field name="vendor_approval_id" readonly="1"/>
+ <field name="vendor_approval_id" readonly="1" widget="many2many_tags"/>
<field name="source_id" domain="[('id', 'in', [32, 59, 60, 61])]" required="1"/>
<button name="override_allow_create_invoice"
string="Override Create Invoice"
@@ -263,9 +263,9 @@
<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">
+ <!-- <page string="Fullfillment" name="page_sale_order_fullfillment">
<field name="fullfillment_line" readonly="1"/>
- </page>
+ </page> -->
<page string="Fulfillment v2" name="page_sale_order_fullfillment2">
<field name="fulfillment_line_v2" readonly="1"/>
</page>
diff --git a/indoteknik_custom/views/stock_picking.xml b/indoteknik_custom/views/stock_picking.xml
index 1893fcaf..562be8d9 100644
--- a/indoteknik_custom/views/stock_picking.xml
+++ b/indoteknik_custom/views/stock_picking.xml
@@ -56,6 +56,11 @@
string="Biteship"
type="object"
/>
+ <button name="track_envio_shipment"
+ string="Tracking Envio"
+ type="object"
+ attrs="{'invisible': [('carrier_id', '!=', 151)]}"
+ />
</button>
<field name="backorder_id" position="after">
<field name="summary_qty_detail"/>
@@ -143,6 +148,24 @@
<field name="sj_documentation" widget="image" />
<field name="paket_documentation" widget="image" />
</group>
+ <group>
+ <field name="envio_id" invisible="1"/>
+ <field name="envio_code"/>
+ <field name="envio_ref_code"/>
+ <field name="envio_eta_at"/>
+ <field name="envio_ata_at"/>
+ <field name="envio_etd_at" invisible="1"/>
+ <field name="envio_atd_at" invisible="1"/>
+ <field name="envio_received_by"/>
+ <field name="envio_status"/>
+ <field name="envio_cod_value" invisible="1"/>
+ <field name="envio_cod_status" invisible="1"/>
+ <field name="envio_latest_message"/>
+ <field name="envio_latest_recorded_at"/>
+ <field name="envio_latest_latitude" invisible="1"/>
+ <field name="envio_latest_longitude" invisible="1"/>
+ <field name="tracking_by" invisible="1"/>
+ </group>
</group>
</page>
</page>
diff --git a/indoteknik_custom/views/vendor_approval.xml b/indoteknik_custom/views/vendor_approval.xml
index 605edfbf..359c67d4 100644
--- a/indoteknik_custom/views/vendor_approval.xml
+++ b/indoteknik_custom/views/vendor_approval.xml
@@ -5,33 +5,24 @@
<field name="name">vendor.approval.tree</field>
<field name="model">vendor.approval</field>
<field name="arch" type="xml">
- <tree default_order="create_date desc" create="0">
+ <tree default_order="create_date desc" create="0" editable="bottom">
<field name="number"/>
<field name="create_date_so"/>
<field name="order_id"/>
<field name="partner_id"/>
- <field name="state"/>
- </tree>
- </field>
- </record>
-
- <record id="vendor_approval_line_tree" model="ir.ui.view">
- <field name="name">vendor.approval.line.tree</field>
- <field name="model">vendor.approval.line</field>
- <field name="arch" type="xml">
- <tree>
+ <field name="state" readonly="1" widget="badge" decoration-danger="state == 'cancel'" decoration-success="state == 'done'"/>
<field name="product_id"/>
- <field name="sales_price"/>
- <field name="product_uom_qty"/>
- <field name="sales_tax_id"/>
- <field name="margin_after"/>
+ <field name="sales_price" optional="hide"/>
+ <field name="product_uom_qty" optional="hide"/>
+ <field name="sales_tax_id" optional="hide"/>
+ <field name="margin_after" optional="hide"/>
<field name="vendor_id"/>
<field name="vendor_md_id"/>
- <field name="purchase_price"/>
- <field name="purchase_price_md"/>
- <field name="margin_before"/>
- <field name="purchase_tax_id"/>
- <field name="percent_margin_difference"/>
+ <field name="purchase_price" optional="hide"/>
+ <field name="purchase_price_md" optional="hide"/>
+ <field name="margin_before" optional="hide"/>
+ <field name="purchase_tax_id" optional="hide"/>
+ <field name="percent_margin_difference" optional="hide"/>
</tree>
</field>
</record>
@@ -60,13 +51,22 @@
<field name="order_id" readonly="1"/>
<field name="state" readonly="1"/>
<field name="create_date_so" readonly="1"/>
+ <field name="product_id"/>
+ <field name="sales_price"/>
+ <field name="product_uom_qty"/>
+ <field name="sales_tax_id"/>
+ </group>
+ <group>
+ <field name="margin_after"/>
+ <field name="vendor_id"/>
+ <field name="vendor_md_id"/>
+ <field name="purchase_price"/>
+ <field name="purchase_price_md"/>
+ <field name="margin_before"/>
+ <field name="purchase_tax_id"/>
+ <field name="percent_margin_difference"/>
</group>
</group>
- <notebook>
- <page string="SO Line">
- <field name="vendor_approval_line" readonly="1"/>
- </page>
- </notebook>
</sheet>
<div class="oe_chatter">
<field name="message_follower_ids" widget="mail_followers"/>
@@ -77,7 +77,7 @@
</record>
<record id="vendor_approval_view_search" model="ir.ui.view">
- <field name="name">vendor.approval.search.view</field> <!-- Made the name more descriptive -->
+ <field name="name">vendor.approval.search.view</field>
<field name="model">vendor.approval</field>
<field name="arch" type="xml">
<search string="Search Vendor Approval">
@@ -102,5 +102,19 @@
sequence="4"
action="vendor_approval_action"
/>
+ <record id="vendor_approval_multi_approve_ir_actions_server" model="ir.actions.server">
+ <field name="name">Approve</field>
+ <field name="model_id" ref="model_vendor_approval"/>
+ <field name="binding_model_id" ref="model_vendor_approval"/>
+ <field name="state">code</field>
+ <field name="code">action = records.open_form_multi_approve()</field>
+ </record>
+ <record id="vendor_approval_multi_reject_ir_actions_server" model="ir.actions.server">
+ <field name="name">Reject</field>
+ <field name="model_id" ref="model_vendor_approval"/>
+ <field name="binding_model_id" ref="model_vendor_approval"/>
+ <field name="state">code</field>
+ <field name="code">action = records.open_form_multi_reject()</field>
+ </record>
</data>
</odoo>