summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFIN-IT_AndriFP <it@fixcomart.co.id>2025-09-29 10:47:25 +0700
committerFIN-IT_AndriFP <it@fixcomart.co.id>2025-09-29 10:47:25 +0700
commite1efb70e0002fec8ad684f7ab62f551f4c649963 (patch)
tree67ddf1ea0cf8294758b552fde26cdcc25630d682
parent6582949e6e8f7017b8b44ed937d6042d8794fbc5 (diff)
parentec21c4721f35028fc9b2a61bd0dbc6e4bf600e74 (diff)
Merge branch 'odoo-backup' of https://bitbucket.org/altafixco/indoteknik-addons into closing-apt
-rw-r--r--indoteknik_api/controllers/api_v1/stock_picking.py58
-rw-r--r--indoteknik_custom/models/account_move_due_extension.py8
-rw-r--r--indoteknik_custom/models/purchasing_job.py19
-rw-r--r--indoteknik_custom/models/refund_sale_order.py133
-rwxr-xr-xindoteknik_custom/models/sale_order.py17
-rw-r--r--indoteknik_custom/models/stock_picking.py5
-rw-r--r--indoteknik_custom/models/tukar_guling.py26
-rw-r--r--indoteknik_custom/report/purchase_report.xml2
-rw-r--r--indoteknik_custom/views/account_move_views.xml3
-rw-r--r--indoteknik_custom/views/stock_picking.xml1
10 files changed, 216 insertions, 56 deletions
diff --git a/indoteknik_api/controllers/api_v1/stock_picking.py b/indoteknik_api/controllers/api_v1/stock_picking.py
index 762e17c5..a4a9cf80 100644
--- a/indoteknik_api/controllers/api_v1/stock_picking.py
+++ b/indoteknik_api/controllers/api_v1/stock_picking.py
@@ -124,33 +124,53 @@ class StockPicking(controller.Controller):
@http.route(prefix + 'stock-picking/<scanid>/documentation', auth='public', methods=['PUT', 'OPTIONS'], csrf=False)
@controller.Controller.must_authorized()
- def write_partner_stock_picking_documentation(self, **kw):
- scanid = kw.get('scanid', '').strip()
- sj_document = kw.get('sj_document', False)
- paket_document = kw.get('paket_document', False)
-
- params = {
- 'sj_documentation': sj_document,
- 'paket_documentation': paket_document,
- 'driver_arrival_date': datetime.utcnow(),
+ def write_partner_stock_picking_documentation(self, scanid, **kw):
+ sj_document = kw.get('sj_document', False)
+ paket_document = kw.get('paket_document', False)
+ dispatch_document = kw.get('dispatch_document', False)
+
+ # ===== Role by EMAIL =====
+ driver_emails = {
+ 'driverindoteknik@gmail.com',
+ 'sulistianaridwan8@gmail.com',
}
+ dispatch_emails = {
+ 'rahmat.afiudin@gmail.com',
+ 'it@fixcomart.co.id'
+ }
+
+ login = (request.env.user.login or '').lower()
+ is_dispatch_user = login in dispatch_emails
+ is_driver_user = (login in driver_emails) and not is_dispatch_user
+
+ # ===== Validasi minimal =====
+ if not sj_document or not paket_document:
+ return self.response(code=400, description='dispatch_document wajib untuk role dispatch login= %s' % login)
+ # if is_dispatch_user and not dispatch_document and not is_driver_user:
+ # return self.response(code=400, description='dispatch_document wajib untuk role dispatch login= %s' % login)
+
+ # ===== Cari picking by id / picking_code =====
picking_data = False
- if scanid.isdigit() and int(scanid) < 2147483647:
- picking_data = request.env['stock.picking'].search([('id', '=', int(scanid))], limit=1)
+ if scanid.isdigit() and int(scanid) < 2147483646:
+ picking_data = request.env['stock.picking'].search([('id', '=', int(scanid))], limit=0)
if not picking_data:
- picking_data = request.env['stock.picking'].search([('picking_code', '=', scanid)], limit=1)
+ picking_data = request.env['stock.picking'].search([('picking_code', '=', scanid)], limit=0)
if not picking_data:
- return self.response(code=404, description='picking not found')
-
- picking_data.write(params)
+ return self.response(code=403, description='picking not found')
- return self.response({
- 'name': picking_data.name
- })
+ params = {
+ 'sj_documentation': sj_document,
+ 'paket_documentation': paket_document,
+ 'driver_arrival_date': datetime.utcnow(),
+ }
+ if dispatch_document:
+ params['dispatch_documentation'] = dispatch_document
+ picking_data.write(params)
+ return self.response({'name': picking_data.name})
@http.route(prefix + 'webhook/biteship', type='json', auth='public', methods=['POST'], csrf=False)
def update_status_from_biteship(self, **kw):
@@ -160,7 +180,7 @@ class StockPicking(controller.Controller):
# Karena type='json', Odoo secara otomatis akan mem-parsing JSON untuk Anda.
# 'data' akan berisi dictionary Python dari payload JSON Biteship.
data = request.jsonrequest
-
+
# Log ini akan menunjukkan payload yang diterima (sudah dalam bentuk dict)
_logger.info(f"Biteship Webhook: Parsed JSON data from request.jsonrequest: {json.dumps(data)}")
diff --git a/indoteknik_custom/models/account_move_due_extension.py b/indoteknik_custom/models/account_move_due_extension.py
index 40059bd9..55fc6c65 100644
--- a/indoteknik_custom/models/account_move_due_extension.py
+++ b/indoteknik_custom/models/account_move_due_extension.py
@@ -13,6 +13,7 @@ class DueExtension(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)
+ payment_term = fields.Char(string="Payment Term", readonly=True, compute='_compute_payment_term')
order_id = fields.Many2one('sale.order', string="SO", readonly=True)
amount_total = fields.Monetary(
string="Amount Total SO",
@@ -43,7 +44,12 @@ class DueExtension(models.Model):
counter = fields.Integer(string="Counter", compute='_compute_counter')
approve_by = fields.Many2one('res.users', string="Approve By", readonly=True)
date_approve = fields.Datetime(string="Date Approve", readonly=True)
-
+
+ @api.depends('partner_id')
+ def _compute_payment_term(self):
+ for rec in self:
+ rec.payment_term = rec.partner_id.property_payment_term_id.name
+
@api.depends('order_id')
def _compute_amount_total(self):
for rec in self:
diff --git a/indoteknik_custom/models/purchasing_job.py b/indoteknik_custom/models/purchasing_job.py
index db733b5a..3151f0f6 100644
--- a/indoteknik_custom/models/purchasing_job.py
+++ b/indoteknik_custom/models/purchasing_job.py
@@ -29,20 +29,23 @@ class PurchasingJob(models.Model):
so_number = fields.Text(string='SO Number', copy=False)
check_pj = fields.Boolean(compute='_get_check_pj', string='Linked')
+
def action_open_job_detail(self):
self.ensure_one()
Seen = self.env['purchasing.job.seen']
+
seen = Seen.search([
- ('user_id', '=', self.env.uid),
('product_id', '=', self.product_id.id)
], limit=1)
if seen:
- seen.so_snapshot = self.so_number
- seen.seen_date = fields.Datetime.now()
+ seen.write({
+ 'so_snapshot': self.so_number,
+ 'seen_date': fields.Datetime.now(),
+ 'user_id': self.env.user.id, })
else:
Seen.create({
- 'user_id': self.env.uid,
+ 'user_id': self.env.user.id,
'product_id': self.product_id.id,
'so_snapshot': self.so_number,
})
@@ -56,17 +59,13 @@ class PurchasingJob(models.Model):
'target': 'current',
}
-
@api.depends('so_number')
def _get_check_pj(self):
+ Seen = self.env['purchasing.job.seen']
for rec in self:
- seen = self.env['purchasing.job.seen'].search([
- ('user_id', '=', self.env.uid),
- ('product_id', '=', rec.product_id.id)
- ], limit=1)
+ seen = Seen.search([('product_id', '=', rec.product_id.id)], limit=1)
rec.check_pj = bool(seen and seen.so_snapshot == rec.so_number)
-
def unlink(self):
# Example: Delete related records from the underlying model
underlying_records = self.env['purchasing.job'].search([
diff --git a/indoteknik_custom/models/refund_sale_order.py b/indoteknik_custom/models/refund_sale_order.py
index 96082447..de9870f6 100644
--- a/indoteknik_custom/models/refund_sale_order.py
+++ b/indoteknik_custom/models/refund_sale_order.py
@@ -303,25 +303,60 @@ class RefundSaleOrder(models.Model):
('journal_id', '=', 7),
('state', '=', 'posted'),
])
+
+ misc = self.env['account.move'].search([
+ ('ref', 'ilike', invoices.mapped('name')[0]),
+ ('ref', 'not ilike', 'reklas'),
+ ('journal_id', '=', 13),
+ ('state', '=', 'posted'),
+ ])
+ moves2 = self.env['account.move']
+ if so_ids:
+ so_names = self.env['sale.order'].browse(so_ids).mapped('name')
+ domain = [
+ ('journal_id', '=', 11),
+ ('state', '=', 'posted'),
+ ('ref', 'ilike', 'dp')
+ ]
+ if so_names:
+ domain += ['|'] * (len(so_names) - 1)
+ for n in so_names:
+ domain.append(('ref', 'ilike', n))
+ moves2 = self.env['account.move'].search(domain)
has_moves = bool(moves)
+ has_moves2 = bool(moves2)
has_piutangmdr = bool(piutangmdr)
has_piutangbca = bool(piutangbca)
+ has_misc = bool(misc)
ssos = self.env['sale.order'].browse(so_ids)
has_settlement = any(so.payment_status == 'settlement' for so in ssos)
sisa_uang_masuk = 0.0
+ amounts = []
+
if has_moves and has_settlement:
- sisa_uang_masuk = sum(moves.mapped('amount_total_signed')) + sum(ssos.mapped('gross_amount'))
- elif has_moves:
- sisa_uang_masuk = sum(moves.mapped('amount_total_signed'))
- elif has_settlement:
- sisa_uang_masuk = sum(ssos.mapped('gross_amount'))
- elif has_piutangbca:
- sisa_uang_masuk = sum(piutangbca.mapped('amount_total_signed'))
- elif has_piutangmdr:
- sisa_uang_masuk = sum(piutangmdr.mapped('amount_total_signed'))
+ amounts.append(sum(moves.mapped('amount_total_signed')))
+ amounts.append(sum(ssos.mapped('gross_amount')))
else:
+ if has_moves:
+ amounts.append(sum(moves.mapped('amount_total_signed')))
+ if has_settlement:
+ amounts.append(sum(ssos.mapped('gross_amount')))
+
+ # sisanya bisa dijumlahkan tanpa konflik
+ if has_moves2:
+ amounts.append(sum(moves2.mapped('amount_total_signed')))
+ if has_piutangbca:
+ amounts.append(sum(piutangbca.mapped('amount_total_signed')))
+ if has_piutangmdr:
+ amounts.append(sum(piutangmdr.mapped('amount_total_signed')))
+ if has_misc:
+ amounts.append(sum(misc.mapped('amount_total_signed')))
+
+ sisa_uang_masuk = sum(amounts)
+
+ if not sisa_uang_masuk:
raise UserError(
"❌ Tidak bisa melakukan refund karena SO tidak memiliki Record Uang Masuk "
"(Journal Uang Muka / Payment Invoices / Midtrans Payment)."
@@ -529,7 +564,32 @@ class RefundSaleOrder(models.Model):
('state', '=', 'posted'),
])
- all_moves = moves | piutangbca | piutangmdr
+ moves2 = self.env['account.move']
+ if rec.sale_order_ids:
+ so_names = rec.sale_order_ids.mapped('name')
+
+ domain = [
+ ('journal_id', '=', 11),
+ ('state', '=', 'posted'),
+ ('ref', 'ilike', 'dp')
+ ]
+ domain += ['|'] * (len(so_names) - 1)
+ for n in so_names:
+ domain.append(('ref', 'ilike', n))
+
+ moves2 = self.env['account.move'].search(domain)
+
+ misc = self.env['account.move']
+ if invoice_ids:
+ invoice_name = invoice_ids.mapped('name')[0]
+ misc = self.env['account.move'].search([
+ ('ref', 'ilike', invoice_name),
+ ('ref', 'not ilike', 'reklas'),
+ ('journal_id', '=', 13),
+ ('state', '=', 'posted'),
+ ])
+
+ all_moves = moves | piutangbca | piutangmdr | misc | moves2
for move in all_moves:
url = f"/web#id={move.id}&model=account.move&view_type=form"
@@ -581,23 +641,54 @@ class RefundSaleOrder(models.Model):
('journal_id', '=', 7),
('state', '=', 'posted'),
])
+ misc = self.env['account.move'].search([
+ ('ref', 'ilike', all_invoices.mapped('name')[0]),
+ ('ref', 'not ilike', 'reklas'),
+ ('journal_id', '=', 13),
+ ('state', '=', 'posted'),
+ ])
+ moves2 = self.env['account.move']
+ if so_ids:
+ so_records = self.env['sale.order'].browse(so_ids)
+ so_names = so_records.mapped('name')
+
+ domain = [
+ ('journal_id', '=', 11),
+ ('state', '=', 'posted'),
+ ('ref', 'ilike', 'dp')
+ ]
+ domain += ['|'] * (len(so_names) - 1)
+ for n in so_names:
+ domain.append(('ref', 'ilike', n))
+
+ moves2 = self.env['account.move'].search(domain)
+
has_moves = bool(moves)
+ has_moves2 = bool(moves2)
has_piutangmdr = bool(piutangmdr)
has_piutangbca = bool(piutangbca)
+ has_misc = bool(misc)
ssos = self.env['sale.order'].browse(so_ids)
has_settlement = any(so.payment_status == 'settlement' for so in ssos)
sisa_uang_masuk = 0.0
- if has_moves and has_settlement:
- sisa_uang_masuk = sum(moves.mapped('amount_total_signed')) + sum(ssos.mapped('gross_amount'))
- elif has_moves:
- sisa_uang_masuk = sum(moves.mapped('amount_total_signed'))
- elif has_settlement:
- sisa_uang_masuk = sum(ssos.mapped('gross_amount'))
- elif has_piutangbca:
- sisa_uang_masuk = sum(piutangbca.mapped('amount_total_signed'))
- elif has_piutangmdr:
- sisa_uang_masuk = sum(piutangmdr.mapped('amount_total_signed'))
+
+ amounts = []
+
+ if has_moves:
+ amounts.append(sum(moves.mapped('amount_total_signed')))
+ if has_moves2:
+ amounts.append(sum(moves2.mapped('amount_total_signed')))
+ if has_piutangbca:
+ amounts.append(sum(piutangbca.mapped('amount_total_signed')))
+ if has_piutangmdr:
+ amounts.append(sum(piutangmdr.mapped('amount_total_signed')))
+ if has_misc:
+ amounts.append(sum(misc.mapped('amount_total_signed')))
+ if has_settlement:
+ amounts.append(sum(ssos.mapped('gross_amount')))
+
+ sisa_uang_masuk = sum(amounts)
self.uang_masuk = sisa_uang_masuk - amount_refund_before
@@ -863,7 +954,7 @@ class RefundSaleOrder(models.Model):
if not rec.status or rec.status == 'draft':
rec.status = 'pengajuan1'
- elif rec.status == 'pengajuan1' and self.env.user.id == 19:
+ elif rec.status == 'pengajuan1' and self.env.user.id in [19, 28]:
rec.status = 'pengajuan2'
rec.approved_by = f"{rec.approved_by}, {user_name}" if rec.approved_by else user_name
rec.date_approved_sales = now
diff --git a/indoteknik_custom/models/sale_order.py b/indoteknik_custom/models/sale_order.py
index f80941d2..663cba58 100755
--- a/indoteknik_custom/models/sale_order.py
+++ b/indoteknik_custom/models/sale_order.py
@@ -3340,10 +3340,17 @@ class SaleOrder(models.Model):
('state', '=', 'posted'),
])
+ moves2 = self.env['account.move'].search([
+ ('ref', 'ilike', self.name),
+ ('journal_id', '=', 11),
+ ('state', '=', 'posted'),
+ ])
+
# Default 0
total_uang_muka = 0.0
has_moves = bool(moves)
+ has_moves2 = bool(moves2)
has_piutangmdr = bool(piutangmdr)
has_piutangbca = bool(piutangbca)
has_settlement = self.payment_status == 'settlement'
@@ -3352,6 +3359,8 @@ class SaleOrder(models.Model):
total_uang_muka = sum(moves.mapped('amount_total_signed')) + self.gross_amount
elif has_moves:
total_uang_muka = sum(moves.mapped('amount_total_signed'))
+ elif has_moves2:
+ total_uang_muka = sum(moves2.mapped('amount_total_signed'))
elif has_settlement:
total_uang_muka = self.gross_amount
elif has_piutangbca:
@@ -3439,12 +3448,20 @@ class SaleOrder(models.Model):
('state', '=', 'posted'),
])
+ moves2 = self.env['account.move'].search([
+ ('ref', 'ilike', order.name),
+ ('journal_id', '=', 11),
+ ('state', '=', 'posted'),
+ ])
+
total_uang_muka = 0.0
if moves and order.payment_status == 'settlement':
total_uang_muka = order.gross_amount + sum(moves.mapped('amount_total_signed')) or 0.0
elif moves:
total_uang_muka = sum(moves.mapped('amount_total_signed')) or 0.0
+ elif moves2:
+ total_uang_muka = sum(moves2.mapped('amount_total_signed')) or 0.0
elif order.payment_status == 'settlement':
total_uang_muka = order.gross_amount
else:
diff --git a/indoteknik_custom/models/stock_picking.py b/indoteknik_custom/models/stock_picking.py
index 67106073..b27e6b5d 100644
--- a/indoteknik_custom/models/stock_picking.py
+++ b/indoteknik_custom/models/stock_picking.py
@@ -89,8 +89,9 @@ class StockPicking(models.Model):
readonly=True,
related="id",
)
- sj_documentation = fields.Binary(string="Dokumentasi Surat Jalan", )
- paket_documentation = fields.Binary(string="Dokumentasi Paket", )
+ sj_documentation = fields.Binary(string="Dokumentasi Surat Jalan")
+ paket_documentation = fields.Binary(string="Dokumentasi Paket")
+ dispatch_documentation = fields.Binary(string="Dokumentasi Dispatch")
sj_return_date = fields.Datetime(string="SJ Return Date", copy=False)
responsible = fields.Many2one('res.users', string='Responsible', tracking=True)
diff --git a/indoteknik_custom/models/tukar_guling.py b/indoteknik_custom/models/tukar_guling.py
index c683f75a..cb630a04 100644
--- a/indoteknik_custom/models/tukar_guling.py
+++ b/indoteknik_custom/models/tukar_guling.py
@@ -538,6 +538,11 @@ class TukarGuling(models.Model):
self.state = 'approval_sales'
def update_doc_state(self):
+ bu_pick = self.env['stock.picking'].search([
+ ('origin', '=', self.operations.origin),
+ ('name', 'ilike', 'BU/PICK'),
+ ])
+
# OUT tukar guling
if self.operations.picking_type_id.id == 29 and self.return_type == 'tukar_guling':
total_out = self.env['stock.picking'].search_count([
@@ -552,7 +557,26 @@ class TukarGuling(models.Model):
if self.state == 'approved' and total_out > 0 and done_out == total_out:
self.state = 'done'
- # OUT revisi SO
+ #SO Lama (gk ada bu pick)
+ elif self.operations.picking_type_id.id == 29 and self.return_type == 'retur_so' and not bu_pick:
+ # so_lama = self.env['sale.order'].search([
+ # ('name', '=', self.operations.origin),
+ # ('state', '=', 'done'),
+ # ('group_id.name', '=', self.operations.origin)
+ # ])
+ total_ort = self.env['stock.picking'].search_count([
+ ('tukar_guling_id', '=', self.id),
+ ('picking_type_id', '=', 74),
+ ])
+ done_srt = self.env['stock.picking'].search([
+ ('tukar_guling_id', '=', self.id),
+ ('picking_type_id', '=', 73),
+ ('state', '=', 'done')
+ ])
+ if self.state == 'approved' and total_ort == 0 and done_srt and not bu_pick:
+ self.state = 'done'
+
+ # OUT retur SO
elif self.operations.picking_type_id.id == 29 and self.return_type == 'retur_so':
total_ort = self.env['stock.picking'].search_count([
('tukar_guling_id', '=', self.id),
diff --git a/indoteknik_custom/report/purchase_report.xml b/indoteknik_custom/report/purchase_report.xml
index 9ff7e718..23fa4d52 100644
--- a/indoteknik_custom/report/purchase_report.xml
+++ b/indoteknik_custom/report/purchase_report.xml
@@ -97,7 +97,7 @@
<!-- TEKS -->
<div style="display:flex; flex-direction:column; flex:1;">
<span style="font-weight:bold; margin-bottom:2px;">
- <t t-esc="line_index + 1"/>. <t t-esc="line.name"/>
+ <t t-esc="line_index + 1"/>. <t t-esc="line.product_id.display_name"/>
</span>
</div>
</td>
diff --git a/indoteknik_custom/views/account_move_views.xml b/indoteknik_custom/views/account_move_views.xml
index 7c1f8913..08b93f1f 100644
--- a/indoteknik_custom/views/account_move_views.xml
+++ b/indoteknik_custom/views/account_move_views.xml
@@ -66,7 +66,8 @@
<group>
<group>
<field name="partner_id" readonly="1"/>
- <field name="day_extension" attrs="{'readonly': [('is_approve', '=', True)]}"/>
+ <field name="payment_term"/>
+ <field name="day_extension" attrs="{'readonly': [('is_approve', '=', True)]}"/>
<field name="order_id" readonly="1"/>
<field name="amount_total" readonly="1"/>
</group>
diff --git a/indoteknik_custom/views/stock_picking.xml b/indoteknik_custom/views/stock_picking.xml
index 0e2eb9e4..21762202 100644
--- a/indoteknik_custom/views/stock_picking.xml
+++ b/indoteknik_custom/views/stock_picking.xml
@@ -235,6 +235,7 @@
<field name='sj_return_date'/>
<field name="sj_documentation" widget="image"/>
<field name="paket_documentation" widget="image"/>
+ <field name="dispatch_documentation" widget="image"/>
</group>
<!-- Biteship Group -->
<group attrs="{'invisible': [('select_shipping_option_so', '!=', 'biteship')]}">