summaryrefslogtreecommitdiff
path: root/indoteknik_custom/models
diff options
context:
space:
mode:
authorit-fixcomart <it@fixcomart.co.id>2025-01-21 13:53:28 +0700
committerit-fixcomart <it@fixcomart.co.id>2025-01-21 13:53:28 +0700
commit63433ff471ba98e6fc63bca16abd9a585471498b (patch)
tree7fe83758b1c40888bab68f5498e4a1c7da4d7891 /indoteknik_custom/models
parentff20b62d6932c6be4ffb56f63f3c05be3aa72c06 (diff)
parente3521c2153c36cee6629cee9146e1b4b0201da9f (diff)
Merge branch 'odoo-production' into CR/form-merchant
# Conflicts: # indoteknik_api/models/res_partner.py # indoteknik_api/models/res_users.py # indoteknik_custom/__manifest__.py # indoteknik_custom/models/__init__.py # indoteknik_custom/models/res_partner.py # indoteknik_custom/security/ir.model.access.csv # indoteknik_custom/views/res_partner.xml # indoteknik_custom/views/user_company_request.xml
Diffstat (limited to 'indoteknik_custom/models')
-rwxr-xr-xindoteknik_custom/models/__init__.py7
-rw-r--r--indoteknik_custom/models/account_move.py47
-rw-r--r--indoteknik_custom/models/account_move_due_extension.py1
-rw-r--r--indoteknik_custom/models/automatic_purchase.py1
-rw-r--r--indoteknik_custom/models/coretax_fatur.py121
-rw-r--r--indoteknik_custom/models/ir_actions_report.py51
-rw-r--r--indoteknik_custom/models/manufacturing.py2
-rwxr-xr-xindoteknik_custom/models/product_template.py2
-rwxr-xr-xindoteknik_custom/models/purchase_order.py159
-rwxr-xr-xindoteknik_custom/models/purchase_order_line.py74
-rw-r--r--indoteknik_custom/models/purchasing_job.py2
-rw-r--r--indoteknik_custom/models/report_stock_forecasted.py49
-rw-r--r--indoteknik_custom/models/res_partner.py254
-rwxr-xr-xindoteknik_custom/models/res_users.py15
-rwxr-xr-xindoteknik_custom/models/sale_order.py20
-rw-r--r--indoteknik_custom/models/sale_order_line.py24
-rw-r--r--indoteknik_custom/models/solr/apache_solr.py2
-rw-r--r--indoteknik_custom/models/stock_immediate_transfer.py36
-rw-r--r--indoteknik_custom/models/stock_picking.py218
-rw-r--r--indoteknik_custom/models/user_company_request.py42
-rw-r--r--indoteknik_custom/models/user_pengajuan_tempo.py134
-rw-r--r--indoteknik_custom/models/user_pengajuan_tempo_line.py12
-rw-r--r--indoteknik_custom/models/user_pengajuan_tempo_request.py630
-rw-r--r--indoteknik_custom/models/website_telegram.py193
24 files changed, 1978 insertions, 118 deletions
diff --git a/indoteknik_custom/models/__init__.py b/indoteknik_custom/models/__init__.py
index 25f56052..714d29d3 100755
--- a/indoteknik_custom/models/__init__.py
+++ b/indoteknik_custom/models/__init__.py
@@ -34,6 +34,7 @@ from . import stock_picking_type
from . import stock_picking
from . import stock_vendor
from . import user_company_request
+from . import user_pengajuan_tempo_request
from . import users
from . import website_brand_homepage
from . import website_categories_homepage
@@ -130,9 +131,15 @@ from . import account_tax
from . import approval_unreserve
from . import vendor_approval
from . import partner
+from . import website_telegram
from . import find_page
+from . import user_pengajuan_tempo_line
+from . import user_pengajuan_tempo
from . import approval_retur_picking
from . import va_multi_approve
from . import va_multi_reject
+from . import stock_immediate_transfer
+from . import coretax_fatur
+from . import ir_actions_report
from . import user_form_merchant
from . import user_merchant_request
diff --git a/indoteknik_custom/models/account_move.py b/indoteknik_custom/models/account_move.py
index 725b3c2d..85ed1d54 100644
--- a/indoteknik_custom/models/account_move.py
+++ b/indoteknik_custom/models/account_move.py
@@ -62,6 +62,16 @@ class AccountMove(models.Model):
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")
+ other_subtotal = fields.Float(string="Other Subtotal", compute='compute_other_subtotal')
+ other_taxes = fields.Float(string="Other Taxes", compute='compute_other_taxes')
+
+ def compute_other_taxes(self):
+ for rec in self:
+ rec.other_taxes = rec.other_subtotal * 0.12
+
+ def compute_other_subtotal(self):
+ for rec in self:
+ rec.other_subtotal = rec.amount_untaxed * (11 / 12)
@api.model
def generate_attachment(self, record):
@@ -253,6 +263,11 @@ class AccountMove(models.Model):
line.date_maturity = entry.date
return res
+ def button_draft(self):
+ res = super(AccountMove, self).button_draft()
+ if not self.env.user.is_accounting:
+ raise UserError("Hanya Finence yang bisa ubah data")
+ return res
def _compute_invoice_day_to_due(self):
for invoice in self:
@@ -325,3 +340,35 @@ class AccountMove(models.Model):
# if rec.statement_line_id and not rec.statement_line_id.statement_id.is_edit and rec.statement_line_id.statement_id.state == 'confirm':
# raise UserError('Bank Statement di Lock, Minta admin reconcile untuk unlock')
# return res
+
+ def validate_faktur_for_export(self):
+ invoices = self.filtered(lambda inv: not inv.is_efaktur_exported and
+ inv.state == 'posted' and
+ inv.move_type == 'out_invoice')
+
+ invalid_invoices = self - invoices
+ if invalid_invoices:
+ invalid_ids = ", ".join(str(inv.id) for inv in invalid_invoices)
+ raise UserError((
+ "Faktur dengan ID berikut tidak valid untuk diekspor: {}.\n"
+ "Pastikan faktur dalam status 'posted', belum diekspor, dan merupakan 'out_invoice'.".format(invalid_ids)
+ ))
+
+ return invoices
+
+ def export_faktur_to_xml(self):
+
+ valid_invoices = self
+
+ # Panggil model coretax.faktur untuk menghasilkan XML
+ coretax_faktur = self.env['coretax.faktur'].create({})
+ response = coretax_faktur.export_to_download(invoices=valid_invoices)
+
+ current_time = datetime.utcnow()
+ # Tandai faktur sebagai sudah diekspor
+ valid_invoices.write({
+ 'is_efaktur_exported': True,
+ 'date_efaktur_exported': current_time, # Set tanggal ekspor
+ })
+
+ return response
diff --git a/indoteknik_custom/models/account_move_due_extension.py b/indoteknik_custom/models/account_move_due_extension.py
index 6fc58cdd..c48c2372 100644
--- a/indoteknik_custom/models/account_move_due_extension.py
+++ b/indoteknik_custom/models/account_move_due_extension.py
@@ -90,6 +90,7 @@ class DueExtension(models.Model):
return self.order_id._create_approval_notification('Pimpinan')
if self.order_id._requires_approval_margin_manager():
+ self.order_id.check_credit_limit()
self.order_id.approval_status = 'pengajuan1'
return self.order_id._create_approval_notification('Sales Manager')
diff --git a/indoteknik_custom/models/automatic_purchase.py b/indoteknik_custom/models/automatic_purchase.py
index 4e96e6d4..09d283eb 100644
--- a/indoteknik_custom/models/automatic_purchase.py
+++ b/indoteknik_custom/models/automatic_purchase.py
@@ -255,6 +255,7 @@ class AutomaticPurchase(models.Model):
'suggest': product._get_po_suggest(line.qty_purchase),
'product_uom_qty': line.qty_purchase,
'price_unit': line.last_price,
+ 'ending_price': line.last_price,
'taxes_id': [line.taxes_id.id] if line.taxes_id else None,
'so_line_id': sales_match[0].sale_line_id.id if sales_match else None,
'so_id': sales_match[0].sale_id.id if sales_match else None
diff --git a/indoteknik_custom/models/coretax_fatur.py b/indoteknik_custom/models/coretax_fatur.py
new file mode 100644
index 00000000..ae6dd2ae
--- /dev/null
+++ b/indoteknik_custom/models/coretax_fatur.py
@@ -0,0 +1,121 @@
+from odoo import models, fields
+import xml.etree.ElementTree as ET
+from xml.dom import minidom
+import base64
+import re
+
+class CoretaxFaktur(models.Model):
+ _name = 'coretax.faktur'
+ _description = 'Export Faktur ke XML'
+
+ export_file = fields.Binary(string="Export File", )
+ export_filename = fields.Char(string="Export File", )
+
+ def validate_and_format_number(slef, input_number):
+ # Hapus semua karakter non-digit
+ cleaned_number = re.sub(r'\D', '', input_number)
+
+ total_sum = sum(int(char) for char in cleaned_number)
+ if total_sum == 0 :
+ return '0000000000000000'
+
+ # Hitung jumlah digit
+ digit_count = len(cleaned_number)
+
+ # Jika jumlah digit kurang dari 15, tambahkan nol di depan
+ if digit_count < 16:
+ cleaned_number = cleaned_number.zfill(16)
+
+ return cleaned_number
+
+ def generate_xml(self, invoices=None):
+ # Buat root XML
+ root = ET.Element('TaxInvoiceBulk', {
+ 'xmlns:xsi': "http://www.w3.org/2001/XMLSchema-instance",
+ 'xsi:noNamespaceSchemaLocation': "TaxInvoice.xsd"
+ })
+ ET.SubElement(root, 'TIN').text = '0742260227086000'
+
+ # Tambahkan elemen ListOfTaxInvoice
+ list_of_tax_invoice = ET.SubElement(root, 'ListOfTaxInvoice')
+
+ # Dapatkan data faktur
+ # inv_obj = self.env['account.move']
+ # invoices = inv_obj.search([('is_efaktur_exported','=',True),
+ # ('state','=','posted'),
+ # ('efaktur_id','!=', False),
+ # ('move_type','=','out_invoice')], limit = 5)
+
+ for invoice in invoices:
+ tax_invoice = ET.SubElement(list_of_tax_invoice, 'TaxInvoice')
+ buyerTIN = self.validate_and_format_number(invoice.partner_id.npwp)
+ nitku = invoice.partner_id.nitku
+ formula = nitku if nitku else buyerTIN.ljust(len(buyerTIN) + 6, '0')
+ buyerIDTKU = formula if sum(int(char) for char in buyerTIN) > 0 else '000000'
+
+ # Tambahkan elemen faktur
+ ET.SubElement(tax_invoice, 'TaxInvoiceDate').text = invoice.invoice_date.strftime('%Y-%m-%d') if invoice.invoice_date else ''
+ ET.SubElement(tax_invoice, 'TaxInvoiceOpt').text = 'Normal'
+ ET.SubElement(tax_invoice, 'TrxCode').text = '04'
+ ET.SubElement(tax_invoice, 'AddInfo')
+ ET.SubElement(tax_invoice, 'CustomDoc')
+ ET.SubElement(tax_invoice, 'RefDesc').text = invoice.name
+ ET.SubElement(tax_invoice, 'FacilityStamp')
+ ET.SubElement(tax_invoice, 'SellerIDTKU').text = '0742260227086000000000'
+ ET.SubElement(tax_invoice, 'BuyerTin').text = buyerTIN
+ ET.SubElement(tax_invoice, 'BuyerDocument').text = 'TIN' if sum(int(char) for char in buyerTIN) > 0 else 'Other ID'
+ ET.SubElement(tax_invoice, 'BuyerCountry').text = 'IDN'
+ ET.SubElement(tax_invoice, 'BuyerDocumentNumber').text = '-' if sum(int(char) for char in buyerTIN) > 0 else str(invoice.partner_id.id)
+ ET.SubElement(tax_invoice, 'BuyerName').text = invoice.partner_id.nama_wajib_pajak or ''
+ ET.SubElement(tax_invoice, 'BuyerAdress').text = invoice.partner_id.alamat_lengkap_text or ''
+ ET.SubElement(tax_invoice, 'BuyerEmail').text = invoice.partner_id.email or ''
+ ET.SubElement(tax_invoice, 'BuyerIDTKU').text = buyerIDTKU
+
+ # Tambahkan elemen ListOfGoodService
+ list_of_good_service = ET.SubElement(tax_invoice, 'ListOfGoodService')
+ for line in invoice.invoice_line_ids:
+ otherTaxBase = round(line.price_subtotal * (11/12)) if line.price_subtotal else 0
+ good_service = ET.SubElement(list_of_good_service, 'GoodService')
+ ET.SubElement(good_service, 'Opt').text = 'A'
+ ET.SubElement(good_service, 'Code')
+ ET.SubElement(good_service, 'Name').text = line.name
+ ET.SubElement(good_service, 'Unit').text = 'UM.0018'
+ ET.SubElement(good_service, 'Price').text = str(round(line.price_subtotal/line.quantity, 2)) if line.price_subtotal else '0'
+ ET.SubElement(good_service, 'Qty').text = str(line.quantity)
+ ET.SubElement(good_service, 'TotalDiscount').text = '0'
+ ET.SubElement(good_service, 'TaxBase').text = str(round(line.price_subtotal)) if line.price_subtotal else '0'
+ ET.SubElement(good_service, 'OtherTaxBase').text = str(otherTaxBase)
+ ET.SubElement(good_service, 'VATRate').text = '12'
+ ET.SubElement(good_service, 'VAT').text = str(round(otherTaxBase * 0.12, 2))
+ ET.SubElement(good_service, 'STLGRate').text = '0'
+ ET.SubElement(good_service, 'STLG').text = '0'
+
+ # Pretty print XML
+ xml_str = ET.tostring(root, encoding='utf-8')
+ xml_pretty = minidom.parseString(xml_str).toprettyxml(indent=" ")
+ return xml_pretty
+
+ def export_to_download(self, invoices):
+ # Generate XML content
+ xml_content = self.generate_xml(invoices)
+
+ # Encode content to Base64
+ xml_encoded = base64.b64encode(xml_content.encode('utf-8'))
+
+ # Buat attachment untuk XML
+ attachment = self.env['ir.attachment'].create({
+ 'name': 'Faktur_XML.xml',
+ 'type': 'binary',
+ 'datas': xml_encoded,
+ 'mimetype': 'application/xml',
+ 'store_fname': 'faktur_xml.xml',
+ })
+
+ # Kembalikan URL untuk download dengan header 'Content-Disposition'
+ response = {
+ 'type': 'ir.actions.act_url',
+ 'url': '/web/content/{}?download=true'.format(attachment.id),
+ 'target': 'self',
+ }
+
+ return response
diff --git a/indoteknik_custom/models/ir_actions_report.py b/indoteknik_custom/models/ir_actions_report.py
new file mode 100644
index 00000000..28adcf74
--- /dev/null
+++ b/indoteknik_custom/models/ir_actions_report.py
@@ -0,0 +1,51 @@
+from odoo import models
+from odoo.http import request
+import requests
+class IrActionsReport(models.Model):
+ _inherit = 'ir.actions.report'
+
+ def _get_readable_fields(self):
+ if self.env.context.get('active_model') == 'sale.order':
+ self.send_to_telegram()
+ return super()._get_readable_fields()
+
+ def send_to_telegram(self):
+ so_id = self.env.context.get('active_id')
+ if so_id:
+ sale_order = self.env['sale.order'].browse(so_id)
+ if sale_order.amount_total < 50000000:
+ return
+ # ci_vita 7751529082:AAE9XsZa_Pj2Pi2IN1grX98WkwTaIt32pbI & 5081411103
+ # iman 7094158106:AAHpWtYOMnA3Yqm_Fvrr3Vw7MrB45vLV9AY & 6592318498
+ # bot_name_iman = '7094158106:AAHpWtYOMnA3Yqm_Fvrr3Vw7MrB45vLV9AY'
+ # chat_id_iman = '6592318498'
+ bot_name_vita = '7751529082:AAE9XsZa_Pj2Pi2IN1grX98WkwTaIt32pbI'
+ chat_id_vita = '5081411103'
+ apiURL = f'https://api.telegram.org/bot{bot_name_vita}/sendMessage'
+ try:
+ requests.post(apiURL, json={'chat_id': chat_id_vita, 'text': sale_order.name + " senilai Rp" + self.format_currency(sale_order.amount_total) + ' untuk customer ' + sale_order.partner_id.name + ' telah dibuat oleh sales ' +sale_order.user_id.name})
+ except Exception as e:
+ print(e)
+
+ # id ci vita 79160
+ # id iman 112718
+ # partner = request.env['res.partner'].search([('id', '=', 112718)], limit=1)
+ # telegram_data = {
+ # 'tittle': sale_order.name,
+ # 'about': sale_order.name,
+ # 'user_id': partner,
+ # 'id_data': sale_order.id,
+ # 'username': '@' + sale_order.name.replace('/', '')
+ # }
+ # channel_data = self.env['website.telegram'].search([('tittle', '=', sale_order.name)])
+ # if channel_data:
+ # channel_data.send_to_telegram(sale_order.name + " Telah di print Oleh " + self.env.user.name)
+ # for pick in self:
+ # self._check_telegram(pick)
+ # else:
+ # telegram = self.env['website.telegram'].create(telegram_data)
+ # telegram.create_channel(sale_order.name + " Telah di print Oleh " + self.env.user.name)
+
+ def format_currency(self, number):
+ number = int(number)
+ return "{:,}".format(number).replace(',', '.') \ No newline at end of file
diff --git a/indoteknik_custom/models/manufacturing.py b/indoteknik_custom/models/manufacturing.py
index 37c4e909..24a8b8c3 100644
--- a/indoteknik_custom/models/manufacturing.py
+++ b/indoteknik_custom/models/manufacturing.py
@@ -30,7 +30,7 @@ class Manufacturing(models.Model):
# if line.quantity_done > 0 and line.quantity_done != self.product_uom_qty:
# raise UserError('Qty Consume per Line tidak sama dengan Qty to Produce')
if line.forecast_availability != line.product_uom_qty:
- raise UserError('Qty Reserved belum sesuai dengan yang seharusnya')
+ raise UserError('Qty Reserved belum sesuai dengan yang seharusnya, product: %s' % line.product_id.display_name)
result = super(Manufacturing, self).button_mark_done()
return result
diff --git a/indoteknik_custom/models/product_template.py b/indoteknik_custom/models/product_template.py
index 9007dd71..5bedae13 100755
--- a/indoteknik_custom/models/product_template.py
+++ b/indoteknik_custom/models/product_template.py
@@ -416,7 +416,7 @@ class ProductProduct(models.Model):
box_size=5,
border=4,
)
- qr.add_data(rec.display_name)
+ qr.add_data(rec.default_code)
qr.make(fit=True)
img = qr.make_image(fill_color="black", back_color="white")
diff --git a/indoteknik_custom/models/purchase_order.py b/indoteknik_custom/models/purchase_order.py
index 0e39d12a..d487ada3 100755
--- a/indoteknik_custom/models/purchase_order.py
+++ b/indoteknik_custom/models/purchase_order.py
@@ -30,6 +30,11 @@ class PurchaseOrder(models.Model):
('pengajuan2', 'Approval Pimpinan'), #akbar - 7 temporary not used
('approved', 'Approved'),
], string='Approval Status', readonly=True, copy=False, index=True, tracking=3)
+ approval_status_unlock = fields.Selection([
+ ('pengajuanFinance', 'Pengajuan Finance'),
+ ('approvedFinance', 'Approved Finance'),
+ ('approved', 'Approved'),
+ ], string='Approval Status Unlock', readonly=True, copy=False, index=True, tracking=3)
delivery_amount = fields.Float('Delivery Amount', compute='compute_delivery_amount')
delivery_amt = fields.Float('Delivery Amt')
total_margin = fields.Float(
@@ -75,7 +80,40 @@ class PurchaseOrder(models.Model):
exclude_incoming = fields.Boolean(string='Exclude Incoming', default=False,
help='Centang jika tidak mau masuk perhitungan Incoming Qty')
not_update_purchasepricelist = fields.Boolean(string='Not Update Purchase Pricelist?')
+ reason_unlock = fields.Char(string='Alasan unlock', tracking=3)
+ # total_cost_service = fields.Float(string='Total Cost Service' )
+ # total_delivery_amt = fields.Float(string='Total Delivery Amt')
+ total_cost_service = fields.Float(string='Total Cost Service')
+ total_delivery_amt = fields.Float(string='Total Delivery Amt')
+ store_name = fields.Char(string='Nama Toko')
+
+ @api.onchange('total_cost_service')
+ def _onchange_total_cost_service(self):
+ for order in self:
+ lines = order.order_line
+ if order.total_cost_service > 0:
+ if lines:
+ # Hitung nilai rata-rata cost_service
+ per_line_cost_service = order.total_cost_service / len(lines)
+ for line in lines:
+ line.cost_service = per_line_cost_service
+ else:
+ for line in lines:
+ line.cost_service = 0
+ @api.onchange('total_delivery_amt')
+ def _onchange_total_delivery_amt(self):
+ for order in self:
+ lines = order.order_line
+ if order.total_delivery_amt > 0:
+ if lines:
+ # Hitung nilai rata-rata delivery_amt
+ per_line_delivery_amt = order.total_delivery_amt / len(lines)
+ for line in lines:
+ line.delivery_amt = per_line_delivery_amt
+ else:
+ for line in lines:
+ line.delivery_amt = 0
def _compute_total_margin_match(self):
for purchase in self:
match = self.env['purchase.order.sales.match']
@@ -115,6 +153,7 @@ class PurchaseOrder(models.Model):
'ref': self.name,
'invoice_date': current_date,
'date': current_date,
+ 'invoice_origin': self.name,
'move_type': 'in_invoice'
}
@@ -165,6 +204,11 @@ class PurchaseOrder(models.Model):
self.bills_pelunasan_id = bills.id
+ lognote_message = (
+ f"Vendor bill created from: {self.name} ({self.partner_ref})"
+ )
+ bills.message_post(body=lognote_message)
+
return {
'name': _('Account Move'),
'view_mode': 'tree,form',
@@ -174,12 +218,10 @@ class PurchaseOrder(models.Model):
'domain': [('id', '=', bills.id)]
}
-
-
def create_bill_dp(self):
if not self.env.user.is_accounting:
raise UserError('Hanya Accounting yang bisa bikin bill dp')
-
+
current_date = datetime.utcnow()
data_bills = {
'partner_id': self.partner_id.id,
@@ -187,8 +229,8 @@ class PurchaseOrder(models.Model):
'ref': self.name,
'invoice_date': current_date,
'date': current_date,
+ 'invoice_origin': self.name,
'move_type': 'in_invoice'
-
}
bills = self.env['account.move'].create([data_bills])
@@ -197,14 +239,13 @@ class PurchaseOrder(models.Model):
data_line_bills = {
'move_id': bills.id,
- 'product_id': product_dp.id, #product down payment
- 'account_id': 401, #Uang Muka persediaan barang dagang
+ 'product_id': product_dp.id, # product down payment
+ 'account_id': 401, # Uang Muka persediaan barang dagang
'quantity': 1,
'product_uom_id': 1,
'tax_ids': [line[0].taxes_id.id for line in self.order_line],
}
-
bills_line = self.env['account.move.line'].create([data_line_bills])
self.bills_dp_id = bills.id
@@ -213,6 +254,12 @@ class PurchaseOrder(models.Model):
move_line.name = '[IT.121456] Down Payment'
move_line.partner_id = self.partner_id.id
+ # Tambahkan lognote
+ lognote_message = (
+ f"Vendor bill created from: {self.name} ({self.partner_ref})"
+ )
+ bills.message_post(body=lognote_message)
+
return {
'name': _('Account Move'),
'view_mode': 'tree,form',
@@ -222,6 +269,7 @@ class PurchaseOrder(models.Model):
'domain': [('id', '=', bills.id)]
}
+
def get_date_done(self):
picking = self.env['stock.picking'].search([
('purchase_id', '=', self.id),
@@ -749,8 +797,12 @@ class PurchaseOrder(models.Model):
def po_approve(self):
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'):
+ if self.approval_status_unlock == 'pengajuanFinance':
+ if self.env.user.is_accounting:
+ self.approval_status_unlock = 'approvedFinance'
+ else:
+ raise UserError("Bisa langsung Confirm, menunggu persetujuan Finance jika ingin unlock PO")
+ elif 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 and not different_vendor_message:
raise UserError("Bisa langsung Confirm")
@@ -779,7 +831,17 @@ class PurchaseOrder(models.Model):
subtype_id=self.env.ref("mail.mt_note").id
)
-
+ def po_approve_unlock(self):
+ if self.approval_status_unlock == 'pengajuanFinance':
+ if self.env.user.is_accounting:
+ self.approval_status_unlock = 'approvedFinance'
+ else:
+ raise UserError("Menunggu persetujuan Finance jika ingin unlock PO")
+ elif self.approval_status_unlock == 'approvedFinance':
+ raise UserError("PO bisa langsung di unlock")
+ else:
+ raise UserError("Menunggu persetujuan Finance jika ingin unlock PO")
+
def check_different_vendor_so(self):
vendor_po = self.partner_id.id
message = ''
@@ -853,6 +915,13 @@ class PurchaseOrder(models.Model):
sales_price -= sale_order_line.fee_third_party_line
sum_sales_price += sales_price
purchase_price = line.price_subtotal
+ if line.ending_price > 0:
+ if line.taxes_id.id == 22:
+ ending_price = line.ending_price / 1.11
+ purchase_price = ending_price
+ else:
+ purchase_price = line.ending_price
+ # purchase_price = line.price_subtotal
if line.order_id.delivery_amount > 0:
purchase_price += line.delivery_amt_line
if line.order_id.delivery_amt > 0:
@@ -896,7 +965,14 @@ class PurchaseOrder(models.Model):
sales_price -= (sale_order_line.fee_third_party_line / sale_order_line.product_uom_qty) * line.qty_po
sum_sales_price += sales_price
- purchase_price = po_line.price_subtotal / po_line.product_qty * line.qty_po
+
+ purchase_price = po_line.price_subtotal
+ if po_line.ending_price > 0:
+ if po_line.taxes_id.id == 22:
+ ending_price = po_line.ending_price / 1.11
+ purchase_price = ending_price
+ else:
+ purchase_price = po_line.ending_price
if line.purchase_order_id.delivery_amount > 0:
purchase_price += (po_line.delivery_amt_line / po_line.product_qty) * line.qty_po
if line.purchase_order_id.delivery_amt > 0:
@@ -915,6 +991,19 @@ class PurchaseOrder(models.Model):
self.total_percent_margin = 0
self.total_so_margin = 0
self.total_so_percent_margin = 0
+
+
+ if sum_so_margin != 0 and sum_sales_price != 0 and sum_margin != 0:
+ self.total_so_margin = sum_so_margin
+ self.total_so_percent_margin = round((sum_so_margin / sum_sales_price), 2) * 100
+ self.total_margin = sum_margin
+ self.total_percent_margin = round((sum_margin / sum_sales_price), 2) * 100
+
+ else:
+ self.total_margin = 0
+ self.total_percent_margin = 0
+ self.total_so_margin = 0
+ self.total_so_percent_margin = 0
def compute_amt_total_without_service(self):
for order in self:
@@ -923,3 +1012,51 @@ class PurchaseOrder(models.Model):
if line.product_id.type == 'product':
sum_price_total += line.price_total
order.amount_total_without_service = sum_price_total
+
+ def button_unlock(self):
+ for order in self:
+ # Check if any order line has received_qty not equal to 0
+ if self.env.user.is_accounting:
+ order.state = 'purchase'
+ order.approval_status_unlock = 'approved'
+ break
+ for line in order.order_line:
+ if line.qty_received > 0:
+ if order.approval_status_unlock == 'approvedFinance':
+ order.approval_status_unlock = 'approved'
+ order.state = 'purchase'
+ break
+ if order.approval_status_unlock == 'pengajuanFinance':
+ raise UserError(_(
+ "Menunggu Approve Dari Finance."
+ ))
+ else:
+ return {
+ 'type': 'ir.actions.act_window',
+ 'name': _('Untuk mengubah PO butuh approve dari Finance. Berikan alasan anda unlock PO!'),
+ 'res_model': 'purchase.order.unlock.wizard',
+ 'view_mode': 'form',
+ 'target': 'new',
+ 'context': {
+ 'default_purchase_order_id': order.id
+ }
+ }
+
+ return super(PurchaseOrder, self).button_unlock()
+
+
+class PurchaseOrderUnlockWizard(models.TransientModel):
+ _name = 'purchase.order.unlock.wizard'
+ _description = 'Wizard untuk memberikan alasan unlock PO'
+
+ purchase_order_id = fields.Many2one('purchase.order', string='Purchase Order', required=True)
+ alasan = fields.Text(string='Alasan', required=True)
+
+ def confirm_reject(self):
+ order = self.purchase_order_id
+ if order:
+ order.write({'reason_unlock': self.alasan})
+ order.approval_status_unlock = 'pengajuanFinance'
+ return {'type': 'ir.actions.act_window_close'}
+
+
diff --git a/indoteknik_custom/models/purchase_order_line.py b/indoteknik_custom/models/purchase_order_line.py
index 9e7d7e81..587a09a1 100755
--- a/indoteknik_custom/models/purchase_order_line.py
+++ b/indoteknik_custom/models/purchase_order_line.py
@@ -43,7 +43,79 @@ class PurchaseOrderLine(models.Model):
qty_reserved = fields.Float(string='Qty Reserved', compute='_compute_qty_reserved')
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')
-
+ delivery_amt = fields.Float(string='Delivery Amt', compute='_compute_doc_delivery_amt')
+ delivery_amt_per_item = fields.Float(string='Delivery Amt Per Item' , compute='_compute_doc_delivery_amt')
+ contribution_delivery_amt = fields.Float(string='Contribution Delivery Amt', compute='_compute_doc_delivery_amt')
+ cost_service = fields.Float(string='Biaya Jasa', compute='_compute_doc_delivery_amt')
+ cost_service_per_item = fields.Float(string='Biaya Jasa Per Item', compute='_compute_doc_delivery_amt')
+ contribution_cost_service = fields.Float(string='Contribution Cost Service', compute='_compute_doc_delivery_amt')
+ ending_price = fields.Float(string='Ending Price', compute='_compute_doc_delivery_amt')
+
+ def _compute_doc_delivery_amt(self):
+ for line in self:
+ # Inisialisasi nilai default untuk field computed
+ line.delivery_amt = 0.0
+ line.delivery_amt_per_item = 0.0
+ line.contribution_delivery_amt = 0.0
+ line.cost_service = 0.0
+ line.cost_service_per_item = 0.0
+ line.contribution_cost_service = 0.0
+ line.ending_price = line.price_unit * line.product_qty
+
+ # Ambil nilai dari order_id
+ total_delivery_amt = line.order_id.total_delivery_amt
+ total_cost_service = line.order_id.total_cost_service
+
+ include_price = line.price_unit * line.product_qty
+ if line.order_id.amount_total > 0:
+ if total_delivery_amt > 0:
+ contributions = include_price / line.order_id.amount_total
+ if line.taxes_id.id == 22:
+ contributions = line.price_subtotal / line.order_id.amount_untaxed
+ contribution = contributions * total_delivery_amt
+ line.delivery_amt = contribution
+ line.delivery_amt_per_item = contribution / line.product_qty
+ line.contribution_delivery_amt = contributions
+
+ if total_cost_service > 0:
+ contributions = include_price / line.order_id.amount_total
+ if line.taxes_id.id == 22:
+ contributions = line.price_subtotal / line.order_id.amount_untaxed
+ contribution = contributions * total_cost_service
+ line.cost_service = contribution
+ line.cost_service_per_item = contribution / line.product_qty
+ line.contribution_cost_service = contributions
+
+ if total_delivery_amt > 0 and total_cost_service > 0:
+ line.ending_price = (line.price_unit + line.delivery_amt_per_item + line.cost_service_per_item) * line.product_qty
+ elif total_delivery_amt > 0 and total_cost_service == 0:
+ line.ending_price = (line.price_unit + line.delivery_amt_per_item) * line.product_qty
+ elif total_delivery_amt == 0 and total_cost_service > 0:
+ line.ending_price = (line.price_unit + line.cost_service_per_item) * line.product_qty
+
+ # @api.constrains('delivery_amt')
+ # def delivery_amt_margin(self):
+ # for line in self:
+ # if line.delivery_amt:
+ # line.delivery_amt_per_item = line.delivery_amt / line.product_qty
+ # line.ending_price = line.price_unit + line.delivery_amt_per_item + line.cost_service
+ # elif line.delivery_amt == 0:
+ # line. delivery_amt_per_item = 0
+ # if line.cost_service:
+ # line.ending_price = line.price_unit + line.cost_service
+ # else:
+ # line.ending_price = line.price_unit
+
+ # @api.constrains('cost_service')
+ # def cost_service_margin(self):
+ # for line in self:
+ # if line.cost_service:
+ # line.ending_price = line.price_unit + line.cost_service + line.delivery_amt_per_item
+ # elif line.cost_service == 0:
+ # if line.delivery_amt_per_item:
+ # line.ending_price = line.price_unit + line.delivery_amt_per_item
+ # else:
+ # line.ending_price = line.price_unit
def _get_clean_website_description_product(self):
for line in self:
description = line.product_id.website_description
diff --git a/indoteknik_custom/models/purchasing_job.py b/indoteknik_custom/models/purchasing_job.py
index 4efb0cd4..74b5134e 100644
--- a/indoteknik_custom/models/purchasing_job.py
+++ b/indoteknik_custom/models/purchasing_job.py
@@ -182,7 +182,7 @@ class OutstandingSales(models.Model):
join product_product pp on pp.id = sm.product_id
join product_template pt on pt.id = pp.product_tmpl_id
left join x_manufactures xm on xm.id = pt.x_manufacture
- where sp.state in ('draft', 'waiting', 'confirmed', 'assigned')
+ where sp.state in ('draft', 'waiting', 'confirmed')
and sp.name like '%OUT%'
)
""")
diff --git a/indoteknik_custom/models/report_stock_forecasted.py b/indoteknik_custom/models/report_stock_forecasted.py
index c9d54a15..37082869 100644
--- a/indoteknik_custom/models/report_stock_forecasted.py
+++ b/indoteknik_custom/models/report_stock_forecasted.py
@@ -1,51 +1,4 @@
from odoo import api, models
class ReplenishmentReport(models.AbstractModel):
- _inherit = 'report.stock.report_product_product_replenishment'
-
- @api.model
- def _get_report_lines(self, product_template_ids, product_variant_ids, wh_location_ids):
- lines = super(ReplenishmentReport, self)._get_report_lines(product_template_ids, product_variant_ids, wh_location_ids)
- # result_dict = {}
- #
- # for line in lines:
- # document_out = line.get('document_out')
- #
- # if document_out and "SO/" in document_out.name:
- # order_id = document_out.id
- # if document_out == False:
- # continue
- # product_id = line.get('product', {}).get('id')
- # query = [('product_id', '=', product_id)]
- #
- # if order_id:
- # result = self._calculate_result(line)
- # quantity = line.get('quantity', 0)
- # result_dict.setdefault(order_id, []).append((result, quantity))
- #
- # for order_id, results in result_dict.items():
- # sales_order = self.env['sale.order'].browse(order_id)
- #
- # for result, quantity in results:
- # self.env['sales.order.fullfillment'].create({
- # 'sales_order_id': sales_order.id,
- # 'product_id': product_id,
- # 'reserved_from': result,
- # 'qty_fullfillment': quantity,
- # })
- return lines
-
- def _calculate_result(self, line):
- if line['document_in']:
- return str(line["document_in"].name)
- elif line['reservation'] and not line['document_in']:
- return 'Reserved from stock'
- elif line['replenishment_filled']:
- if line['document_out']:
- return 'Inventory On Hand'
- else:
- return 'Free Stock'
- else:
- return 'Unfulfilled'
-
-
+ _inherit = 'report.stock.report_product_product_replenishment' \ No newline at end of file
diff --git a/indoteknik_custom/models/res_partner.py b/indoteknik_custom/models/res_partner.py
index d7bd260f..8a420048 100644
--- a/indoteknik_custom/models/res_partner.py
+++ b/indoteknik_custom/models/res_partner.py
@@ -20,6 +20,78 @@ class ResPartner(models.Model):
domain="[('internal_type', '=', 'receivable'), ('deprecated', '=', False), ('company_id', '=', current_company_id)]",
help="This account will be used instead of the default one as the receivable account for the current partner",
default=395)
+ # Referensi
+ supplier_ids = fields.Many2many('user.pengajuan.tempo.line', string="Suppliers")
+
+ # informasi perusahaan
+ name_tempo = fields.Many2one('res.partner', string='Nama Perusahaan',tracking=True)
+ industry_id_tempo = fields.Many2one('res.partner.industry', 'Customer Industry', readonly=True)
+ street_tempo = fields.Char(string="Alamat Perusahaan")
+ state_id_tempo = fields.Many2one('res.country.state', string='State')
+ city_id_tempo = fields.Many2one('vit.kota', string='City')
+ zip_tempo = fields.Char(string="Zip")
+ mobile_tempo = fields.Char(string="No. Telfon Perusahaan")
+ bank_name_tempo = fields.Char(string="Nama Bank")
+ account_name_tempo = fields.Char(string="Nama Rekening")
+ account_number_tempo = fields.Char(string="Nomor Rekening Bank")
+ website_tempo = fields.Char(string='Website')
+ portal = fields.Boolean(string='Portal Website')
+ estimasi_tempo = fields.Char(string='Estimasi Pembelian Pertahun')
+ tempo_duration = fields.Many2one('account.payment.term', string='Durasi Tempo')
+ tempo_limit = fields.Char(string='Limit Tempo')
+ category_produk_ids = fields.Many2many('product.public.category', string='Kategori Produk yang Digunakan', domain=lambda self: self._get_default_category_domain())
+
+ @api.model
+ def _get_default_category_domain(self):
+ return [('parent_id', '=', False)]
+
+ # Kontak Perusahaan
+ direktur_name = fields.Char(string='Nama Lengkap Direktur')
+ direktur_mobile = fields.Char(string='No. Telpon Direktur')
+ direktur_email = fields.Char(string='Email Direktur')
+ purchasing_name = fields.Char(string='Nama Purchasing')
+ purchasing_mobile = fields.Char(string='No. Telpon Purchasing')
+ purchasing_email = fields.Char(string='Email Purchasing')
+ finance_name = fields.Char(string='Nama Finance')
+ finance_mobile = fields.Char(string='No. Telpon Finance')
+ finance_email = fields.Char(string='Email Finance')
+
+ # Pengiriman
+ pic_name = fields.Char(string='Nama PIC Penerimaan Barang')
+ street_pengiriman = fields.Char(string="Alamat Perusahaan")
+ state_id_pengiriman = fields.Many2one('res.country.state', string='State')
+ city_id_pengiriman = fields.Many2one('vit.kota', string='City')
+ district_id_pengiriman = fields.Many2one('vit.kecamatan', string='Kecamatan')
+ subDistrict_id_pengiriman = fields.Many2one('vit.kelurahan', string='Kelurahan')
+ zip_pengiriman = fields.Char(string="Zip")
+ invoice_pic = fields.Char(string='Nama PIC Penerimaan Invoice')
+ street_invoice = fields.Char(string="Alamat Perusahaan")
+ state_id_invoice = fields.Many2one('res.country.state', string='State')
+ city_id_invoice = fields.Many2one('vit.kota', string='City')
+ district_id_invoice = fields.Many2one('vit.kecamatan', string='Kecamatan')
+ subDistrict_id_invoice = fields.Many2one('vit.kelurahan', string='Kelurahan')
+ zip_invoice = fields.Char(string="Zip")
+ tukar_invoice = fields.Char(string='Jadwal Penukaran Invoice')
+ jadwal_bayar = fields.Char(string='Jadwal Pembayaran')
+ dokumen_pengiriman = fields.Char(string='Dokumen Tanda Terima yang Diberikan Pada Saat Pengiriman Barang')
+ dokumen_pengiriman_input = fields.Char(string='Dokumen yang Dibawa Saat Pengiriman Barang')
+ dokumen_invoice = fields.Char(string='Dokumen yang dilampirkan saat Pengiriman Invoice')
+
+ # Dokumen
+ dokumen_npwp = fields.Many2one('ir.attachment', string="NPWP Perusahaan", tracking=3, readonly=True)
+ dokumen_sppkp = fields.Many2one('ir.attachment', string="SPPKP Perusahaan", tracking=3, readonly=True)
+ dokumen_nib = fields.Many2one('ir.attachment', string="NIB (SIUP/TDP/SKDP)", tracking=3, readonly=True,)
+ dokumen_siup = fields.Many2one('ir.attachment', string="SIUP Perusahaan", tracking=3, readonly=True)
+ dokumen_tdp = fields.Many2one('ir.attachment', string="TDP Perusahaan", tracking=3, readonly=True)
+ dokumen_skdp = fields.Many2one('ir.attachment', string="SKDP Perusahaan",tracking=True, readonly=True)
+ dokumen_skt = fields.Many2one('ir.attachment', string="SKT Perusahaan", tracking=True, readonly=True)
+ dokumen_akta_perubahan = fields.Many2one('ir.attachment', string="Akta Perubahan", tracking=3, readonly=True)
+ dokumen_ktp_dirut = fields.Many2one('ir.attachment', string="KTP Dirut/Direktur", tracking=3, readonly=True)
+ dokumen_akta_pendirian = fields.Many2one('ir.attachment', string="Akta Pendirian", tracking=3, readonly=True)
+ dokumen_laporan_keuangan = fields.Many2one('ir.attachment', string="Laporan Keuangan", tracking=3, readonly=True)
+ dokumen_foto_kantor = fields.Many2one('ir.attachment', string=" Foto Kantor (Tampak Depan)", tracking=3, readonly=True)
+ dokumen_tempat_bekerja = fields.Many2one('ir.attachment', string="Tempat Bekerja", tracking=3, readonly=True)
+
reference_number = fields.Char(string="Reference Number")
company_type_id = fields.Many2one('res.partner.company_type', string='Company Type')
custom_pricelist_id = fields.Many2one('product.pricelist', string='Price Matrix')
@@ -30,6 +102,7 @@ class ResPartner(models.Model):
])
sppkp = fields.Char(string="SPPKP", tracking=True)
npwp = fields.Char(string="NPWP", tracking=True)
+ nitku = fields.Char(string="NITKU", tracking=True)
counter = fields.Integer(string="Counter", default=0)
leadtime = fields.Integer(string="Leadtime", default=0)
digital_invoice_tax = fields.Boolean(string="Digital Invoice & Faktur Pajak")
@@ -74,6 +147,7 @@ class ResPartner(models.Model):
"customer is crossed blocking amount."
"Set its value to 0.00 to disable "
"this feature", tracking=3)
+ telegram_id = fields.Char(string="Telegram")
# MERCHANT
# informasi perusahaan
@@ -114,9 +188,12 @@ class ResPartner(models.Model):
file_kartuNama = fields.Binary(string="Kartu Nama", tracking=True, track_visibility="onchange")
file_npwp = fields.Binary(string="NPWP", tracking=True, track_visibility="onchange")
file_sppkp = fields.Binary(string="SPPKP", tracking=True, track_visibility="onchange")
- file_suratPernyataan = fields.Binary(string="Surat Pernyataan Nomor Rekening", tracking=True, track_visibility="onchange")
- file_fotoKantor = fields.Binary(string="Foto Gudang / Kantor Bagian Depan", tracking=True, track_visibility="onchange")
- file_dataProduk = fields.Binary(string="Data Produk (Item Name, Gambar, Deskripsi)", tracking=True,track_visibility="onchange")
+ file_suratPernyataan = fields.Binary(string="Surat Pernyataan Nomor Rekening", tracking=True,
+ track_visibility="onchange")
+ file_fotoKantor = fields.Binary(string="Foto Gudang / Kantor Bagian Depan", tracking=True,
+ track_visibility="onchange")
+ file_dataProduk = fields.Binary(string="Data Produk (Item Name, Gambar, Deskripsi)", tracking=True,
+ track_visibility="onchange")
file_pricelist = fields.Binary(string="Pricelist", tracking=True, track_visibility="onchange")
description = fields.Text(string='Deskripsi')
@@ -137,23 +214,22 @@ class ResPartner(models.Model):
if partner.company_type == 'person' and not partner.parent_id:
partner.alamat_lengkap_text = partner.street
# if partner.company_type == 'person' and partner.parent_id:
- # partner.alamat_lengkap_text = partner.parent_id.alamat_lengkap_text
-
+ # partner.alamat_lengkap_text = partner.parent_id.alamat_lengkap_text
- alamat_lengkap_text = fields.Text(string="Alamat Lengkap", required=False , tracking=3)
+ alamat_lengkap_text = fields.Text(string="Alamat Lengkap", required=False, tracking=3)
def write(self, vals):
res = super(ResPartner, self).write(vals)
- #
- # # if 'property_payment_term_id' in vals:
- # # if not self.env.user.is_accounting and vals['property_payment_term_id'] != 26:
- # # raise UserError('Hanya Finance Accounting yang dapat merubah payment term')
- #
- # # group_id = self.env.ref('indoteknik_custom.group_role_merchandiser').id
- # # users_in_group = self.env['res.users'].search([('groups_id', 'in', [group_id])])
- # # if self.env.user.id not in users_in_group.mapped('id'):
- # # raise UserError('You name it')
- #
+ #
+ # # if 'property_payment_term_id' in vals:
+ # # if not self.env.user.is_accounting and vals['property_payment_term_id'] != 26:
+ # # raise UserError('Hanya Finance Accounting yang dapat merubah payment term')
+ #
+ # # group_id = self.env.ref('indoteknik_custom.group_role_merchandiser').id
+ # # users_in_group = self.env['res.users'].search([('groups_id', 'in', [group_id])])
+ # # if self.env.user.id not in users_in_group.mapped('id'):
+ # # raise UserError('You name it')
+ #
return res
def write(self, vals):
@@ -178,8 +254,74 @@ class ResPartner(models.Model):
vals['sppkp'] = vals.get('sppkp', self.sppkp)
vals['alamat_lengkap_text'] = vals.get('alamat_lengkap_text', self.alamat_lengkap_text)
vals['industry_id'] = vals.get('industry_id', self.industry_id.id if self.industry_id else None)
- vals['company_type_id'] = vals.get('company_type_id',
- self.company_type_id.id if self.company_type_id else None)
+ vals['company_type_id'] = vals.get('company_type_id', self.company_type_id.id if self.company_type_id else None)
+
+ # Referensi
+ vals['supplier_ids'] = vals.get('supplier_ids', self.supplier_ids)
+
+ # informasi perusahaan
+ vals['name_tempo'] = vals.get('name_tempo', self.name_tempo)
+ vals['industry_id_tempo'] = vals.get('industry_id_tempo', self.industry_id_tempo)
+ vals['street_tempo'] = vals.get('street_tempo', self.street_tempo)
+ vals['state_id_tempo'] = vals.get('state_id_tempo', self.state_id_tempo)
+ vals['city_id_tempo'] = vals.get('city_id_tempo', self.city_id_tempo)
+ vals['zip_tempo'] = vals.get('zip_tempo', self.zip_tempo)
+ vals['bank_name_tempo'] = vals.get('bank_name_tempo', self.bank_name_tempo)
+ vals['account_name_tempo'] = vals.get('account_name_tempo', self.account_name_tempo)
+ vals['account_number_tempo'] = vals.get('account_number_tempo', self.account_number_tempo)
+ vals['website_tempo'] = vals.get('website_tempo', self.website_tempo)
+ vals['portal'] = vals.get('portal', self.portal)
+ vals['estimasi_tempo'] = vals.get('estimasi_tempo', self.estimasi_tempo)
+ vals['tempo_duration'] = vals.get('tempo_duration', self.tempo_duration)
+ vals['tempo_limit'] = vals.get('tempo_limit', self.tempo_limit)
+ vals['category_produk_ids'] = vals.get('category_produk_ids', self.category_produk_ids)
+
+ # Kontak Perusahaan
+ vals['direktur_name'] = vals.get('direktur_name', self.direktur_name)
+ vals['direktur_mobile'] = vals.get('direktur_mobile', self.direktur_mobile)
+ vals['direktur_email'] = vals.get('direktur_email', self.direktur_email)
+ vals['purchasing_name'] = vals.get('purchasing_name', self.purchasing_name)
+ vals['purchasing_mobile'] = vals.get('purchasing_mobile', self.purchasing_mobile)
+ vals['purchasing_email'] = vals.get('purchasing_email', self.purchasing_email)
+ vals['finance_name'] = vals.get('finance_name', self.finance_name)
+ vals['finance_mobile'] = vals.get('finance_mobile', self.finance_mobile)
+ vals['finance_email'] = vals.get('finance_email', self.finance_email)
+
+ # Pengiriman
+ vals['pic_name'] = vals.get('pic_name', self.pic_name)
+ vals['street_pengiriman'] = vals.get('street_pengiriman', self.street_pengiriman)
+ vals['state_id_pengiriman'] = vals.get('state_id_pengiriman', self.state_id_pengiriman)
+ vals['city_id_pengiriman'] = vals.get('city_id_pengiriman', self.city_id_pengiriman)
+ vals['district_id_pengiriman'] = vals.get('district_id_pengiriman', self.district_id_pengiriman)
+ vals['subDistrict_id_pengiriman'] = vals.get('subDistrict_id_pengiriman', self.subDistrict_id_pengiriman)
+ vals['zip_pengiriman'] = vals.get('zip_pengiriman', self.zip_pengiriman)
+ vals['invoice_pic'] = vals.get('invoice_pic', self.invoice_pic)
+ vals['street_invoice'] = vals.get('street_invoice', self.street_invoice)
+ vals['state_id_invoice'] = vals.get('state_id_invoice', self.state_id_invoice)
+ vals['city_id_invoice'] = vals.get('city_id_invoice', self.city_id_invoice)
+ vals['district_id_invoice'] = vals.get('district_id_invoice', self.district_id_invoice)
+ vals['subDistrict_id_invoice'] = vals.get('subDistrict_id_invoice', self.subDistrict_id_invoice)
+ vals['zip_invoice'] = vals.get('zip_invoice', self.zip_invoice)
+ vals['tukar_invoice'] = vals.get('tukar_invoice', self.tukar_invoice)
+ vals['jadwal_bayar'] = vals.get('jadwal_bayar', self.jadwal_bayar)
+ vals['dokumen_pengiriman'] = vals.get('dokumen_pengiriman', self.dokumen_pengiriman)
+ vals['dokumen_pengiriman_input'] = vals.get('dokumen_pengiriman_input', self.dokumen_pengiriman_input)
+ vals['dokumen_invoice'] = vals.get('dokumen_invoice', self.dokumen_invoice)
+
+ # Dokumen
+ vals['dokumen_npwp'] = vals.get('dokumen_npwp', self.dokumen_npwp)
+ vals['dokumen_sppkp'] = vals.get('dokumen_sppkp', self.dokumen_sppkp)
+ vals['dokumen_nib'] = vals.get('dokumen_nib', self.dokumen_nib)
+ vals['dokumen_siup'] = vals.get('dokumen_siup', self.dokumen_siup)
+ vals['dokumen_tdp'] = vals.get('dokumen_tdp', self.dokumen_tdp)
+ vals['dokumen_skdp'] = vals.get('dokumen_skdp', self.dokumen_skdp)
+ vals['dokumen_skt'] = vals.get('dokumen_skt', self.dokumen_skt)
+ vals['dokumen_akta_perubahan'] = vals.get('dokumen_akta_perubahan', self.dokumen_akta_perubahan)
+ vals['dokumen_ktp_dirut'] = vals.get('dokumen_ktp_dirut', self.dokumen_ktp_dirut)
+ vals['dokumen_akta_pendirian'] = vals.get('dokumen_akta_pendirian', self.dokumen_akta_pendirian)
+ vals['dokumen_laporan_keuangan'] = vals.get('dokumen_laporan_keuangan', self.dokumen_laporan_keuangan)
+ vals['dokumen_foto_kantor'] = vals.get('dokumen_foto_kantor', self.dokumen_foto_kantor)
+ vals['dokumen_tempat_bekerja'] = vals.get('dokumen_tempat_bekerja', self.dokumen_tempat_bekerja)
# Merchant
vals['name_merchant'] = vals.get('name_merchant', self.name_merchant)
@@ -209,7 +351,6 @@ class ResPartner(models.Model):
vals['file_pricelist'] = vals.get('file_pricelist', self.file_pricelist)
vals['description'] = vals.get('description', self.description)
-
# Simpan hanya field yang perlu di-update pada child
vals_for_child = {
'customer_type': vals.get('customer_type'),
@@ -219,6 +360,66 @@ class ResPartner(models.Model):
'alamat_lengkap_text': vals.get('alamat_lengkap_text'),
'industry_id': vals.get('industry_id'),
'company_type_id': vals.get('company_type_id'),
+ 'supplier_ids': vals.get('supplier_ids'),
+ 'name_tempo': vals.get('name_tempo'),
+ 'industry_id_tempo': vals.get('industry_id_tempo'),
+ 'street_tempo': vals.get('street_tempo'),
+ 'state_id_tempo': vals.get('state_id_tempo'),
+ 'city_id_tempo': vals.get('city_id_tempo'),
+ 'zip_tempo': vals.get('zip_tempo'),
+ 'bank_name_tempo': vals.get('bank_name_tempo'),
+ 'account_name_tempo': vals.get('account_name_tempo'),
+ 'account_number_tempo': vals.get('account_number_tempo'),
+ 'website_tempo': vals.get('website_tempo'),
+ 'portal': vals.get('portal'),
+ 'estimasi_tempo': vals.get('estimasi_tempo'),
+ 'tempo_duration': vals.get('tempo_duration'),
+ 'tempo_limit': vals.get('tempo_limit'),
+ 'category_produk_ids': vals.get('category_produk_ids'),
+ 'direktur_name': vals.get('direktur_name'),
+ 'direktur_mobile': vals.get('direktur_mobile'),
+ 'direktur_email': vals.get('direktur_email'),
+ 'purchasing_name': vals.get('purchasing_name'),
+ 'purchasing_mobile': vals.get('purchasing_mobile'),
+ 'purchasing_email': vals.get('purchasing_email'),
+ 'finance_name': vals.get('finance_name'),
+ 'finance_mobile': vals.get('finance_mobile'),
+ 'finance_email': vals.get('finance_email'),
+ 'pic_name': vals.get('pic_name'),
+ 'street_pengiriman': vals.get('street_pengiriman'),
+ 'state_id_pengiriman': vals.get('state_id_pengiriman'),
+ 'city_id_pengiriman': vals.get('city_id_pengiriman'),
+ 'district_id_pengiriman': vals.get('district_id_pengiriman'),
+ 'subDistrict_id_pengiriman': vals.get('subDistrict_id_pengiriman'),
+ 'zip_pengiriman': vals.get('zip_pengiriman'),
+ 'invoice_pic': vals.get('invoice_pic'),
+ 'street_invoice': vals.get('street_invoice'),
+ 'state_id_invoice': vals.get('state_id_invoice'),
+ 'city_id_invoice': vals.get('city_id_invoice'),
+ 'district_id_invoice': vals.get('district_id_invoice'),
+ 'subDistrict_id_invoice': vals.get('subDistrict_id_invoice'),
+ 'zip_invoice': vals.get('zip_invoice'),
+ 'tukar_invoice': vals.get('tukar_invoice'),
+ 'jadwal_bayar': vals.get('jadwal_bayar'),
+ 'dokumen_pengiriman': vals.get('dokumen_pengiriman'),
+ 'dokumen_pengiriman_input': vals.get('dokumen_pengiriman_input'),
+ 'dokumen_invoice': vals.get('dokumen_invoice'),
+ 'dokumen_npwp': vals.get('dokumen_npwp'),
+ 'dokumen_sppkp': vals.get('dokumen_sppkp'),
+ 'dokumen_nib': vals.get('dokumen_nib'),
+ 'dokumen_siup': vals.get('dokumen_siup'),
+ 'dokumen_tdp': vals.get('dokumen_tdp'),
+ 'dokumen_skdp': vals.get('dokumen_skdp'),
+ 'dokumen_skt': vals.get('dokumen_skt'),
+ 'dokumen_akta_perubahan': vals.get('dokumen_akta_perubahan'),
+ 'dokumen_ktp_dirut': vals.get('dokumen_ktp_dirut'),
+ 'dokumen_akta_pendirian': vals.get('dokumen_akta_pendirian'),
+ 'dokumen_laporan_keuangan': vals.get('dokumen_laporan_keuangan'),
+ 'dokumen_foto_kantor': vals.get('dokumen_foto_kantor'),
+ 'dokumen_tempat_bekerja': vals.get('dokumen_tempat_bekerja'),
+
+ # internal_notes
+ 'comment': vals.get('comment'),
# Merchant
'name_merchant': vals.get('name_merchant'),
@@ -243,7 +444,6 @@ class ResPartner(models.Model):
'file_suratPernyataan': vals.get('file_suratPernyataan'),
'file_fotoKantor': vals.get('file_fotoKantor'),
'description': vals.get('description'),
-
}
# Lakukan update pada semua child secara rekursif
@@ -344,13 +544,17 @@ class ResPartner(models.Model):
if self.customer_type == 'nonpkp':
self.npwp = '00.000.000.0-000.000'
- def get_check_tempo_partner(self):
+ def get_check_payment_term(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
+ return partner.property_payment_term_id.name if partner.property_payment_term_id.id else 'Cash Before Delivery (C.B.D)'
+ @api.constrains('nitku')
+ def _onchange_nitku(self):
+ if self.nitku:
+ if not self.nitku.isdigit():
+ raise UserError("NITKU harus berupa angka.")
+ if len(self.nitku) != 22:
+ raise UserError("NITKU harus memiliki tepat 22 angka.") \ No newline at end of file
diff --git a/indoteknik_custom/models/res_users.py b/indoteknik_custom/models/res_users.py
index 5e16aad1..31b84ae3 100755
--- a/indoteknik_custom/models/res_users.py
+++ b/indoteknik_custom/models/res_users.py
@@ -36,16 +36,31 @@ class ResUsers(models.Model):
for user in self:
template.send_mail(user.id, force_send=True)
+ def send_company_request_mail_switch(self):
+ template = self.env.ref('indoteknik_custom.mail_template_res_user_company_request_switch')
+ for user in self:
+ template.send_mail(user.id, force_send=True)
+
def send_company_request_approve_mail(self):
template = self.env.ref('indoteknik_custom.mail_template_res_user_company_request_approve')
for user in self:
template.send_mail(user.id, force_send=True)
+ def send_company_switch_approve_mail(self):
+ template = self.env.ref('indoteknik_custom.mail_template_res_user_company_switch_approve')
+ for user in self:
+ template.send_mail(user.id, force_send=True)
+
def send_company_request_reject_mail(self):
template = self.env.ref('indoteknik_custom.mail_template_res_user_company_request_reject')
for user in self:
template.send_mail(user.id, force_send=True)
+ def send_company_request_tempo_review(self):
+ template = self.env.ref('indoteknik_custom.mail_template_res_user_company_tempo_review')
+ for user in self:
+ template.send_mail(user.id, force_send=True)
+
def get_activation_token_url(self):
base_url = self.env['ir.config_parameter'].get_param('site.base.url')
return f'{base_url}/register?activation=token&amp;token={self.activation_token}'
diff --git a/indoteknik_custom/models/sale_order.py b/indoteknik_custom/models/sale_order.py
index f5e7e8a1..48195b77 100755
--- a/indoteknik_custom/models/sale_order.py
+++ b/indoteknik_custom/models/sale_order.py
@@ -816,6 +816,7 @@ class SaleOrder(models.Model):
order.approval_status = 'pengajuan2'
return self._create_approval_notification('Pimpinan')
elif order._requires_approval_margin_manager():
+ self.check_credit_limit()
order.approval_status = 'pengajuan1'
return self._create_approval_notification('Sales Manager')
@@ -1031,8 +1032,9 @@ class SaleOrder(models.Model):
if self.have_outstanding_invoice:
raise UserError("Invoice harus di Cancel dahulu")
- elif self.have_outstanding_picking:
- raise UserError("DO harus di Cancel dahulu")
+ for line in self.order_line:
+ if line.qty_delivered > 0:
+ raise UserError("DO harus di-cancel terlebih dahulu.")
if not self.web_approval:
self.web_approval = 'company'
@@ -1410,4 +1412,16 @@ class SaleOrder(models.Model):
'npwp': partner.npwp,
'email': partner.email,
'customer_type': partner.customer_type,
- }) \ No newline at end of file
+ })
+
+ def write(self, vals):
+ for order in self:
+ if order.state in ['sale', 'cancel']:
+ if 'order_line' in vals:
+ new_lines = vals.get('order_line', [])
+ for command in new_lines:
+ if command[0] == 0: # A new line is being added
+ raise UserError(
+ "SO tidak dapat ditambahkan produk baru karena SO sudah menjadi sale order.")
+ res = super(SaleOrder, self).write(vals)
+ return res \ No newline at end of file
diff --git a/indoteknik_custom/models/sale_order_line.py b/indoteknik_custom/models/sale_order_line.py
index a31ff569..aed95aab 100644
--- a/indoteknik_custom/models/sale_order_line.py
+++ b/indoteknik_custom/models/sale_order_line.py
@@ -38,6 +38,14 @@ class SaleOrderLine(models.Model):
md_vendor_id = fields.Many2one('res.partner', string='MD Vendor', readonly=True)
margin_md = fields.Float(string='Margin MD')
qty_free_bu = fields.Float(string='Free BU', compute='_get_qty_free_bandengan')
+ desc_updatable = fields.Boolean(string='desc boolean', default=True, compute='_get_desc_updatable')
+
+ def _get_desc_updatable(self):
+ for line in self:
+ if line.product_id.id != 417724 and line.product_id.id:
+ line.desc_updatable = False
+ else:
+ line.desc_updatable = True
def _get_qty_free_bandengan(self):
for line in self:
@@ -272,6 +280,10 @@ class SaleOrderLine(models.Model):
(line.product_id.short_spesification if line.product_id.short_spesification else '')
line.name = line_name
line.weight = line.product_id.weight
+ if line.product_id.id != 417724 and line.product_id.id:
+ line.desc_updatable = False
+ else:
+ line.desc_updatable = True
@api.constrains('vendor_id')
def _check_vendor_id(self):
@@ -378,4 +390,14 @@ class SaleOrderLine(models.Model):
if not line.product_id.product_tmpl_id.sale_ok:
raise UserError('Product %s belum bisa dijual, harap hubungi finance' % line.product_id.display_name)
if not line.vendor_id or not line.purchase_price and not line.display_type == 'line_note':
- raise UserError(_('Isi Vendor dan Harga Beli sebelum Request Approval')) \ No newline at end of file
+ raise UserError(_('Isi Vendor dan Harga Beli sebelum Request Approval'))
+
+ @api.depends('state')
+ def _compute_product_updatable(self):
+ for line in self:
+ if line.state == 'draft':
+ line.product_updatable = True
+ # line.desc_updatable = True
+ else:
+ line.product_updatable = False
+ # line.desc_updatable = False
diff --git a/indoteknik_custom/models/solr/apache_solr.py b/indoteknik_custom/models/solr/apache_solr.py
index 6560c9b5..d111c1c1 100644
--- a/indoteknik_custom/models/solr/apache_solr.py
+++ b/indoteknik_custom/models/solr/apache_solr.py
@@ -22,7 +22,7 @@ class ApacheSolr(models.Model):
url = ''
if env == 'development':
- url = 'http://192.168.23.5:8983/solr/'
+ url = 'http://localhost:8983/solr/'
elif env == 'production':
url = 'http://34.101.189.218:8983/solr/'
diff --git a/indoteknik_custom/models/stock_immediate_transfer.py b/indoteknik_custom/models/stock_immediate_transfer.py
new file mode 100644
index 00000000..4be0dff2
--- /dev/null
+++ b/indoteknik_custom/models/stock_immediate_transfer.py
@@ -0,0 +1,36 @@
+from odoo import models, api, _
+from odoo.exceptions import UserError
+
+class StockImmediateTransfer(models.TransientModel):
+ _inherit = 'stock.immediate.transfer'
+
+ def process(self):
+ """Override process method to add send_mail_bills logic."""
+ pickings_to_do = self.env['stock.picking']
+ pickings_not_to_do = self.env['stock.picking']
+
+ for line in self.immediate_transfer_line_ids:
+ if line.to_immediate is True:
+ pickings_to_do |= line.picking_id
+ else:
+ pickings_not_to_do |= line.picking_id
+
+ for picking in pickings_to_do:
+ picking.send_mail_bills()
+ # If still in draft => confirm and assign
+ if picking.state == 'draft':
+ picking.action_confirm()
+ if picking.state != 'assigned':
+ picking.action_assign()
+ if picking.state != 'assigned':
+ raise UserError(_("Could not reserve all requested products. Please use the 'Mark as Todo' button to handle the reservation manually."))
+ for move in picking.move_lines.filtered(lambda m: m.state not in ['done', 'cancel']):
+ for move_line in move.move_line_ids:
+ move_line.qty_done = move_line.product_uom_qty
+
+ pickings_to_validate = self.env.context.get('button_validate_picking_ids')
+ if pickings_to_validate:
+ pickings_to_validate = self.env['stock.picking'].browse(pickings_to_validate)
+ pickings_to_validate = pickings_to_validate - pickings_not_to_do
+ return pickings_to_validate.with_context(skip_immediate=True).button_validate()
+ return True
diff --git a/indoteknik_custom/models/stock_picking.py b/indoteknik_custom/models/stock_picking.py
index e6506a0b..cd330aeb 100644
--- a/indoteknik_custom/models/stock_picking.py
+++ b/indoteknik_custom/models/stock_picking.py
@@ -6,10 +6,17 @@ from itertools import groupby
import pytz, requests, json, requests
from dateutil import parser
import datetime
-
+import hmac
+import hashlib
+import base64
+import requests
+import time
+import logging
+_logger = logging.getLogger(__name__)
class StockPicking(models.Model):
_inherit = 'stock.picking'
+ # check_product_lines = fields.One2many('check.product', 'picking_id', string='Check Product', auto_join=True)
is_internal_use = fields.Boolean('Internal Use', help='flag which is internal use or not')
account_id = fields.Many2one('account.account', string='Account')
efaktur_id = fields.Many2one('vit.efaktur', string='Faktur Pajak')
@@ -115,6 +122,19 @@ class StockPicking(models.Model):
], string='Status Reserve', readonly=True, tracking=True, help="The current state of the stock picking.")
notee = fields.Text(string="Note")
+ @api.model
+ def _compute_dokumen_tanda_terima(self):
+ for picking in self:
+ picking.dokumen_tanda_terima = picking.partner_id.dokumen_pengiriman
+
+ @api.model
+ def _compute_dokumen_pengiriman(self):
+ for picking in self:
+ picking.dokumen_pengiriman = picking.partner_id.dokumen_pengiriman_input
+
+ dokumen_tanda_terima = fields.Char(string='Dokumen Tanda Terima yang Diberikan Pada Saat Pengiriman Barang', readonly=True, compute=_compute_dokumen_tanda_terima)
+ dokumen_pengiriman = fields.Char(string='Dokumen yang Dibawa Saat Pengiriman Barang', readonly=True, compute=_compute_dokumen_pengiriman)
+
# Envio Tracking Section
envio_id = fields.Char(string="Envio ID", readonly=True)
envio_code = fields.Char(string="Envio Code", readonly=True)
@@ -134,6 +154,86 @@ class StockPicking(models.Model):
envio_latest_longitude = fields.Float(string="Log Longitude", readonly=True)
tracking_by = fields.Many2one('res.users', string='Tracking By', readonly=True, tracking=True)
+ # Lalamove Section
+ lalamove_order_id = fields.Char(string="Lalamove Order ID", copy=False)
+ lalamove_address = fields.Char(string="Lalamove Address")
+ lalamove_name = fields.Char(string="Lalamove Name")
+ lalamove_phone = fields.Char(string="Lalamove Phone")
+ lalamove_status = fields.Char(string="Lalamove Status")
+ lalamove_delivered_at = fields.Datetime(string="Lalamove Delivered At")
+ lalamove_data = fields.Text(string="Lalamove Data", readonly=True)
+ lalamove_image_url = fields.Char(string="Lalamove Image URL")
+ lalamove_image_html = fields.Html(string="Lalamove Image", compute="_compute_lalamove_image_html")
+
+ def _compute_lalamove_image_html(self):
+ for record in self:
+ if record.lalamove_image_url:
+ record.lalamove_image_html = f'<img src="{record.lalamove_image_url}" width="300" height="300"/>'
+ else:
+ record.lalamove_image_html = "No image available."
+
+ def action_fetch_lalamove_order(self):
+ pickings = self.env['stock.picking'].search([
+ ('picking_type_code', '=', 'outgoing'),
+ ('state', '=', 'done'),
+ ('carrier_id', '=', 9)
+ ])
+ for picking in pickings:
+ try:
+ order_id = picking.lalamove_order_id
+ apikey = self.env['ir.config_parameter'].sudo().get_param('lalamove.apikey')
+ secret = self.env['ir.config_parameter'].sudo().get_param('lalamove.secret')
+ market = self.env['ir.config_parameter'].sudo().get_param('lalamove.market', default='ID')
+
+ order_data = picking.get_lalamove_order(order_id, apikey, secret, market)
+ picking.lalamove_data = order_data
+ except Exception as e:
+ _logger.error(f"Error fetching Lalamove order for picking {picking.id}: {str(e)}")
+ continue
+
+ def get_lalamove_order(self, order_id, apikey, secret, market):
+ timestamp = str(int(time.time() * 1000))
+ message = f"{timestamp}\r\nGET\r\n/v3/orders/{order_id}\r\n\r\n"
+ signature = hmac.new(secret.encode('utf-8'), message.encode('utf-8'), hashlib.sha256).hexdigest()
+
+ headers = {
+ "Content-Type": "application/json",
+ "Authorization": f"hmac {apikey}:{timestamp}:{signature}",
+ "Market": market
+ }
+
+ url = f"https://rest.lalamove.com/v3/orders/{order_id}"
+ response = requests.get(url, headers=headers)
+
+ if response.status_code == 200:
+ data = response.json()
+ stops = data.get("data", {}).get("stops", [])
+
+ for stop in stops:
+ pod = stop.get("POD", {})
+ if pod.get("status") == "DELIVERED":
+ image_url = pod.get("image") # Sesuaikan jika key berbeda
+ self.lalamove_image_url = image_url
+
+ address = stop.get("address")
+ name = stop.get("name")
+ phone = stop.get("phone")
+ delivered_at = pod.get("deliveredAt")
+
+ delivered_at_dt = self._convert_to_datetime(delivered_at)
+
+ self.lalamove_address = address
+ self.lalamove_name = name
+ self.lalamove_phone = phone
+ self.lalamove_status = pod.get("status")
+ self.lalamove_delivered_at = delivered_at_dt
+ return data
+
+ raise UserError("No delivered data found in Lalamove response.")
+ else:
+ raise UserError(f"Error {response.status_code}: {response.text}")
+
+
def _convert_to_wib(self, date_str):
"""
Mengonversi string waktu ISO 8601 ke format waktu Indonesia (WIB)
@@ -661,13 +761,13 @@ class StockPicking(models.Model):
if not self.env.user.is_logistic_approver and self.env.context.get('active_model') == 'stock.picking':
if self.origin and 'Return of' in self.origin:
raise UserError("Button ini hanya untuk Logistik")
-
+
if self.picking_type_code == 'internal':
self.check_qty_done_stock()
if self._name != 'stock.picking':
return super(StockPicking, self).button_validate()
-
+
if not self.picking_code:
self.picking_code = self.env['ir.sequence'].next_by_code('stock.picking.code') or '0'
@@ -681,15 +781,10 @@ class StockPicking(models.Model):
raise UserError("Harus di Approve oleh Accounting")
if self.picking_type_id.id == 28 and not self.env.user.is_logistic_approver:
- raise UserError("Harus di Approve oleh Logistik")
+ raise UserError("Harus di Approve oleh Logistik")
if self.location_dest_id.id == 47 and not self.env.user.is_purchasing_manager:
- raise UserError("Transfer ke gudang selisih harus di approve Rafly Hanggara")
-
- # if self.group_id.sale_id:
- # if self.group_id.sale_id.payment_link_midtrans:
- # if self.group_id.sale_id.payment_status != 'settlement' and self.group_id.sale_id.state == 'draft':
- # raise UserError('Uang belum masuk (settlement), mohon konfirmasi ke sales atau finance')
+ raise UserError("Transfer ke gudang selisih harus di approve Rafly Hanggara")
if self.is_internal_use:
self.approval_status = 'approved'
@@ -707,7 +802,7 @@ class StockPicking(models.Model):
if not self.date_reserved:
current_time = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
self.date_reserved = current_time
-
+
self.validation_minus_onhand_quantity()
self.responsible = self.env.user.id
res = super(StockPicking, self).button_validate()
@@ -715,6 +810,59 @@ class StockPicking(models.Model):
self.date_done = datetime.datetime.utcnow()
self.state_reserve = 'done'
return res
+
+
+ def send_mail_bills(self):
+ if self.picking_type_code == 'incoming' and self.purchase_id:
+ template = self.env.ref('indoteknik_custom.mail_template_invoice_po_document')
+ if template and self.purchase_id:
+ # Render email body
+ email_values = template.sudo().generate_email(
+ res_ids=[self.purchase_id.id],
+ fields=['body_html']
+ )
+ rendered_body = email_values.get(self.purchase_id.id, {}).get('body_html', '')
+
+ # Render report dengan XML ID
+ report = self.env.ref('purchase.action_report_purchase_order') # Gunakan XML ID laporan
+ if not report:
+ raise UserError("Laporan dengan XML ID 'purchase.action_report_purchase_order' tidak ditemukan.")
+
+ # Render laporan ke PDF
+ pdf_content, _ = report._render_qweb_pdf([self.purchase_id.id])
+ report_content = base64.b64encode(pdf_content).decode('utf-8')
+
+ # Kirim email menggunakan template
+ email_sent = template.sudo().send_mail(self.purchase_id.id, force_send=True)
+
+ if email_sent:
+ # Buat attachment untuk laporan
+ attachment = self.env['ir.attachment'].create({
+ 'name': self.purchase_id.name or "Laporan Invoice.pdf",
+ 'type': 'binary',
+ 'datas': report_content,
+ 'res_model': 'purchase.order',
+ 'res_id': self.purchase_id.id,
+ 'mimetype': 'application/pdf',
+ })
+
+ # Siapkan data untuk mail.compose.message
+ compose_values = {
+ 'subject': "Pengiriman Email Invoice",
+ 'body': rendered_body,
+ 'attachment_ids': [(4, attachment.id)],
+ 'res_id': self.purchase_id.id,
+ 'model': 'purchase.order',
+ }
+
+ # Buat mail.compose.message
+ compose_message = self.env['mail.compose.message'].create(compose_values)
+
+ # Kirim pesan melalui wizard
+ compose_message.action_send_mail()
+
+ return True
+
def action_cancel(self):
if not self.env.user.is_logistic_approver and self.env.context.get('active_model') == 'stock.picking':
if self.origin and 'Return of' in self.origin:
@@ -858,4 +1006,50 @@ class StockPicking(models.Model):
formatted_fastest_eta = fastest_eta.strftime(format_time_fastest)
formatted_longest_eta = longest_eta.strftime(format_time)
- return f'{formatted_fastest_eta} - {formatted_longest_eta}' \ No newline at end of file
+ return f'{formatted_fastest_eta} - {formatted_longest_eta}'
+
+# class CheckProduct(models.Model):
+# _name = 'check.product'
+# _description = 'Check Product'
+# _order = 'picking_id, id'
+
+# picking_id = fields.Many2one('stock.picking', string='Picking Reference', required=True, ondelete='cascade', index=True, copy=False)
+# product_id = fields.Many2one('product.product', string='Product')
+
+
+# @api.constrains('product_id')
+# def check_product_validity(self):
+# """
+# Validate if the product exists in the related stock.picking's move_ids_without_package
+# and ensure that the product's quantity does not exceed the available product_uom_qty.
+# """
+# for record in self:
+# if not record.picking_id or not record.product_id:
+# continue
+
+# # Filter move lines in the related picking for the selected product
+# moves = record.picking_id.move_ids_without_package.filtered(
+# lambda move: move.product_id.id == record.product_id.id
+# )
+
+# if not moves:
+# raise UserError((
+# "The product '%s' is not available in the related stock picking's moves. "
+# "Please check and try again."
+# ) % record.product_id.display_name)
+
+# # Calculate the total entries for the product in check.product for the same picking
+# product_entries_count = self.search_count([
+# ('picking_id', '=', record.picking_id.id),
+# ('product_id', '=', record.product_id.id)
+# ])
+
+# # Sum the product_uom_qty for all relevant moves
+# total_qty_in_moves = sum(moves.mapped('product_uom_qty'))
+
+# # Compare the count of entries against the available quantity
+# if product_entries_count > total_qty_in_moves:
+# raise UserError((
+# "The product '%s' exceeds the allowable quantity (%s) in the related stock picking's moves. "
+# "You can only add it %s times."
+# ) % (record.product_id.display_name, total_qty_in_moves, total_qty_in_moves))
diff --git a/indoteknik_custom/models/user_company_request.py b/indoteknik_custom/models/user_company_request.py
index dd9a35c1..af8a86ba 100644
--- a/indoteknik_custom/models/user_company_request.py
+++ b/indoteknik_custom/models/user_company_request.py
@@ -14,7 +14,7 @@ class UserCompanyRequest(models.Model):
('rejected', 'Reject'),
], string='Approval')
similar_company_ids = fields.Many2many('res.partner', compute="_compute_similar_companies", string="Similar Companies")
-
+ is_switch_account = fields.Boolean( string='Switch Account', default=False)
@api.depends('user_input')
def _compute_similar_companies(self):
for record in self:
@@ -64,6 +64,7 @@ class UserCompanyRequest(models.Model):
user.parent_name = self.user_input
is_approve = vals.get('is_approve')
is_internal_input = vals.get('internal_input')
+ is_company_id = vals.get('user_company_id')
if self.is_approve and is_approve:
raise UserError('Tidak dapat mengubah approval yang sudah diisi')
@@ -71,22 +72,37 @@ class UserCompanyRequest(models.Model):
if self.user_company_id.nama_wajib_pajak == self.user_company_id.name:
self.user_company_id.nama_wajib_pajak = is_internal_input
self.user_company_id.name = is_internal_input
+ user_company_id = []
+ if is_company_id:
+ user_company_id = request.env['res.partner'].search([('id', '=', is_company_id)], limit=1)
+ # self.user_company_id.customer_type = self.similar_company_ids.customer_type
+ # self.user_company_id.npwp = self.similar_company_ids.npwp
+ # self.user_company_id.sppkp = self.similar_company_ids.sppkp
+ # self.user_company_id.nama_wajib_pajak = self.similar_company_ids.nama_wajib_pajak
+ # self.user_company_id.alamat_lengkap_text = self.similar_company_ids.alamat_lengkap_text
+ # self.user_company_id.industry_id = self.similar_company_ids.industry_id
+ # self.user_company_id.company_type_id = self.similar_company_ids.company_type_id
+ # self.user_company_id.user_id = self.similar_company_ids.user_id
+ # self.user_company_id.property_account_receivable_id = self.similar_company_ids.property_account_receivable_id
+ # self.user_company_id.property_account_payable_id = self.similar_company_ids.property_account_payable_id
if not self.is_approve and is_approve:
if is_approve == 'approved':
- self.user_id.parent_id = vals.get('user_company_id') if vals.get('user_company_id') else self.user_company_id.id
- self.user_id.customer_type = self.user_company_id.customer_type
- self.user_id.npwp = self.user_company_id.npwp
- self.user_id.sppkp = self.user_company_id.sppkp
- self.user_id.nama_wajib_pajak = self.user_company_id.nama_wajib_pajak
- self.user_id.alamat_lengkap_text = self.user_company_id.alamat_lengkap_text
- self.user_id.industry_id = self.user_company_id.industry_id.id
- self.user_id.company_type_id = self.user_company_id.company_type_id.id
- self.user_id.user_id = self.user_company_id.user_id
- self.user_id.property_account_receivable_id = self.user_company_id.property_account_receivable_id
- self.user_id.property_account_payable_id = self.user_company_id.property_account_payable_id
+ self.user_id.parent_id = user_company_id if user_company_id else self.user_company_id
+ self.user_id.customer_type = user_company_id.customer_type if user_company_id else self.user_company_id.customer_type
+ self.user_id.npwp = user_company_id.npwp if user_company_id else self.user_company_id.npwp
+ self.user_id.sppkp = user_company_id.sppkp if user_company_id else self.user_company_id.sppkp
+ self.user_id.nama_wajib_pajak = user_company_id.nama_wajib_pajak if user_company_id else self.user_company_id.nama_wajib_pajak
+ self.user_id.alamat_lengkap_text = user_company_id.alamat_lengkap_text if user_company_id else self.user_company_id.alamat_lengkap_text
+ self.user_id.industry_id = user_company_id.industry_id.id if user_company_id else self.user_company_id.industry_id
+ self.user_id.company_type_id = user_company_id.company_type_id.id if user_company_id else self.user_company_id.company_type_id
+ self.user_id.user_id = user_company_id.user_id if user_company_id else self.user_company_id.user_id
+ self.user_id.property_account_receivable_id = user_company_id.property_account_receivable_id if user_company_id else self.user_company_id.property_account_receivable_id
+ self.user_id.property_account_payable_id = user_company_id.property_account_payable_id if user_company_id else self.user_company_id.property_account_payable_id
+ self.user_id.property_payment_term_id = user_company_id.property_payment_term_id if user_company_id else self.user_company_id.property_payment_term_id
+ self.user_id.property_supplier_payment_term_id = user_company_id.property_supplier_payment_term_id if user_company_id else self.user_company_id.property_supplier_payment_term_id
self.user_company_id.active = True
- user.send_company_request_approve_mail()
+ user.send_company_switch_approve_mail() if vals.get('is_switch_account') == True else user.send_company_request_approve_mail()
else:
new_company = self.env['res.partner'].create({
'name': self.user_input
diff --git a/indoteknik_custom/models/user_pengajuan_tempo.py b/indoteknik_custom/models/user_pengajuan_tempo.py
new file mode 100644
index 00000000..0fdcdbeb
--- /dev/null
+++ b/indoteknik_custom/models/user_pengajuan_tempo.py
@@ -0,0 +1,134 @@
+from odoo import models, fields, api
+from datetime import datetime, timedelta
+
+
+# class IrAttachment(models.Model):
+# _inherit = 'ir.attachment'
+#
+# @api.model
+# def create(self, vals):
+# attachment = super(IrAttachment, self).create(vals)
+# if attachment:
+# base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url')
+# attachment.url = f"/web/content/{attachment.id}"
+# return attachment
+
+
+class UserPengajuanTempo(models.Model):
+ _name = 'user.pengajuan.tempo'
+ _inherit = ['mail.thread', 'mail.activity.mixin']
+ partner_id = fields.Char()
+ _description = 'User Pengajuan Tempo'
+
+ name = fields.Char(string='Name')
+
+ # informasi perusahaan
+ # name_tempo = fields.Many2one(
+ # 'res.partner', string='Nama Perusahaan',
+ # readonly=True, required=True,
+ # states={'draft': [('readonly', False)], 'sent': [('readonly', False)], 'sale': [('readonly', False)]},
+ # domain="['|', ('company_id', '=', False), ('company_id', '=', company_id)]",
+ # tracking=True, # Menambahkan tracking=True
+ # )
+ name_tempo = fields.Many2one(
+ 'res.partner', string='Nama Perusahaan',
+ tracking=True, # Menambahkan tracking=True
+ )
+ user_id = fields.Many2one('res.users', string='User')
+ industry_id_tempo = fields.Many2one('res.partner.industry', 'Customer Industry', readonly=True)
+ street_tempo = fields.Char(string="Alamat Perusahaan")
+ state_id_tempo = fields.Many2one('res.country.state', string='State')
+ city_id_tempo = fields.Many2one('vit.kota', string='City')
+ district_id_tempo = fields.Many2one('vit.kecamatan', string='Kecamatan')
+ subDistrict_id_tempo = fields.Many2one('vit.kelurahan', string='Kelurahan')
+ zip_tempo = fields.Char(string="Zip")
+ mobile_tempo = fields.Char(string="No. Telfon Perusahaan")
+ bank_name_tempo = fields.Char(string="Nama Bank")
+ account_name_tempo = fields.Char(string="Nama Rekening")
+ account_number_tempo = fields.Char(string="Nomor Rekening Bank")
+ website_tempo = fields.Char(string='Website')
+ portal = fields.Boolean(string='Portal Website')
+ bersedia = fields.Char(string='Website')
+ estimasi_tempo = fields.Char(string='Estimasi Pembelian Pertahun')
+ tempo_duration = fields.Many2one('account.payment.term', string='Durasi Tempo')
+ tempo_limit = fields.Char(string='Limit Tempo')
+ category_produk_ids = fields.Many2many('product.public.category', string='Kategori Produk yang Digunakan', domain=lambda self: self._get_default_category_domain())
+
+ @api.model
+ def _get_default_category_domain(self):
+ return [('parent_id', '=', False)]
+
+ # Kontak Perusahaan
+ direktur_tittle = fields.Char(string='tittle Direktur')
+ direktur_name = fields.Char(string='Nama Lengkap Direktur')
+ direktur_mobile = fields.Char(string='No. Telpon Direktur')
+ direktur_email = fields.Char(string='Email Direktur')
+ purchasing_tittle = fields.Char(string='tittle Purchasing')
+ purchasing_name = fields.Char(string='Nama Purchasing')
+ purchasing_mobile = fields.Char(string='No. Telpon Purchasing')
+ purchasing_email = fields.Char(string='Email Purchasing')
+ finance_tittle = fields.Char(string='tittle Finance')
+ finance_name = fields.Char(string='Nama Finance')
+ finance_mobile = fields.Char(string='No. Telpon Finance')
+ finance_email = fields.Char(string='Email Finance')
+
+ # Pengiriman
+ pic_tittle = fields.Char(string='Tittle PIC Penerimaan Barang')
+ pic_name = fields.Char(string='Nama PIC Penerimaan Barang')
+ street_pengiriman = fields.Char(string="Alamat Perusahaan")
+ state_id_pengiriman = fields.Many2one('res.country.state', string='State')
+ city_id_pengiriman = fields.Many2one('vit.kota', string='City')
+ district_id_pengiriman = fields.Many2one('vit.kecamatan', string='Kecamatan')
+ subDistrict_id_pengiriman = fields.Many2one('vit.kelurahan', string='Kelurahan')
+ zip_pengiriman = fields.Char(string="Zip")
+ invoice_pic_tittle = fields.Char(string='Tittle PIC Penerimaan Invoice')
+ invoice_pic = fields.Char(string='Nama PIC Penerimaan Invoice')
+ street_invoice = fields.Char(string="Alamat Perusahaan")
+ state_id_invoice = fields.Many2one('res.country.state', string='State')
+ city_id_invoice = fields.Many2one('vit.kota', string='City')
+ district_id_invoice = fields.Many2one('vit.kecamatan', string='Kecamatan')
+ subDistrict_id_invoice = fields.Many2one('vit.kelurahan', string='Kelurahan')
+ zip_invoice = fields.Char(string="Zip")
+ tukar_invoice = fields.Char(string='Jadwal Penukaran Invoice')
+ jadwal_bayar = fields.Char(string='Jadwal Pembayaran')
+ dokumen_pengiriman = fields.Char(string='Dokumen Tanda Terima yang Diberikan Pada Saat Pengiriman Barang')
+ dokumen_kirim_input = fields.Char(string='Dokumen lain yang diterima saat pengiriman barang')
+ dokumen_pengiriman_input = fields.Char(string='Dokumen yang Dibawa Saat Pengiriman Barang')
+ dokumen_invoice = fields.Char(string='Dokumen yang dilampirkan saat Pengiriman Invoice')
+ is_same_address = fields.Boolean(string="Same Address pengiriman invoicr dan alamat pengiriman barang")
+ is_same_address_street = fields.Boolean(string="Same Address pengiriman barang dan alamat bisnis")
+
+ # Referensi
+ supplier_ids = fields.Many2many('user.pengajuan.tempo.line', string="Suppliers")
+
+ #Dokumen
+ dokumen_nib = fields.Many2many('ir.attachment', 'pengajuan_dokumen_nib_rel', string="NIB", tracking=True, track_visibility="onchange")
+ dokumen_npwp = fields.Many2many('ir.attachment', 'pengajuan_dokumen_npwp_rel', string="NPWP Perusahaan", tracking=True)
+ dokumen_sppkp = fields.Many2many('ir.attachment', 'pengajuan_dokumen_sppkp_rel', string="SPPKP Perusahaan", tracking=True)
+ dokumen_siup = fields.Many2many('ir.attachment', 'pengajuan_dokumen_siup_rel', string="SIUP Perusahaan", tracking=True)
+ dokumen_tdp = fields.Many2many('ir.attachment', 'pengajuan_dokumen_tdp_rel', string="TDP Perusahaan", tracking=True)
+ dokumen_skdp = fields.Many2many('ir.attachment', 'pengajuan_dokumen_skdp_rel', string="SKDP Perusahaan", tracking=True)
+ dokumen_skt = fields.Many2many('ir.attachment', 'pengajuan_dokumen_skt_rel', string="SKT Perusahaan", tracking=True)
+ dokumen_akta_perubahan = fields.Many2many('ir.attachment', 'pengajuan_dokumen_akta_perubahan_rel',
+ string="Akta Perubahan", tracking=True)
+ dokumen_ktp_dirut = fields.Many2many('ir.attachment', 'pengajuan_dokumen_ktp_dirut_rel',
+ string="KTP Dirut/Direktur", tracking=True)
+ dokumen_akta_pendirian = fields.Many2many('ir.attachment', 'pengajuan_dokumen_angkta_pendirian_rel',
+ string="Akta Pendirian", tracking=True)
+ dokumen_laporan_keuangan = fields.Many2many('ir.attachment', 'pengajuan_dokumen_laporan_keuangan_rel',
+ string="Laporan Keuangan", tracking=True)
+ dokumen_foto_kantor = fields.Many2many('ir.attachment', 'pengajuan_dokumen_foto_kantor_rel',
+ string=" Foto Kantor (Tampak Depan)", tracking=True)
+ dokumen_tempat_bekerja = fields.Many2many('ir.attachment', 'pengajuan_dokumen_tempat_bekerja_rel',
+ string="Tempat Bekerja", tracking=True)
+
+ @api.depends('name', 'name_tempo')
+ def name_get(self):
+ result = []
+ for record in self:
+ if record.name_tempo:
+ display_name = f"DETAIL FORM TEMPO - {record.name_tempo.name}"
+ else:
+ display_name = "DETAIL FORM TEMPO"
+ result.append((record.id, display_name))
+ return result
diff --git a/indoteknik_custom/models/user_pengajuan_tempo_line.py b/indoteknik_custom/models/user_pengajuan_tempo_line.py
new file mode 100644
index 00000000..db519ed6
--- /dev/null
+++ b/indoteknik_custom/models/user_pengajuan_tempo_line.py
@@ -0,0 +1,12 @@
+from odoo import models, fields
+
+
+class PengajuanTempoLine(models.Model):
+ _name = 'user.pengajuan.tempo.line'
+
+ # Fields untuk tabel supplier
+ name_supplier = fields.Char(string="Nama Supplier")
+ pic_name = fields.Char(string="PIC")
+ phone = fields.Char(string="Telepon")
+ tempo_duration = fields.Char(string="Durasi Tempo")
+ credit_limit = fields.Char(string="Credit Limit") \ No newline at end of file
diff --git a/indoteknik_custom/models/user_pengajuan_tempo_request.py b/indoteknik_custom/models/user_pengajuan_tempo_request.py
new file mode 100644
index 00000000..b43f56ac
--- /dev/null
+++ b/indoteknik_custom/models/user_pengajuan_tempo_request.py
@@ -0,0 +1,630 @@
+from odoo import models, fields, api, _
+from odoo.exceptions import UserError
+from odoo.http import request
+
+class RejectReasonWizard(models.TransientModel):
+ _name = 'reject.reason.wizard'
+ _description = 'Wizard for Reject Reason'
+
+ request_id = fields.Many2one('user.pengajuan.tempo.request', string='Request')
+ reason_reject = fields.Text(string='Reason for Rejection', required=True)
+
+ def confirm_reject(self):
+ tempo = self.request_id
+ if tempo:
+ tempo.write({'reason_reject': self.reason_reject})
+ tempo.state_tempo = 'reject'
+ template = self.env.ref('indoteknik_custom.mail_template_res_user_company_tempo_reject')
+ template.send_mail(tempo.id, force_send=True)
+ return {'type': 'ir.actions.act_window_close'}
+class ConfirmApprovalWizard(models.TransientModel):
+ _name = 'confirm.approval.wizard'
+ _description = 'Wizard Konfirmasi Approval'
+
+ tempo_id = fields.Many2one('user.pengajuan.tempo.request', string='Tempo', required=True)
+
+ def confirm_approval(self):
+ tempo = self.tempo_id
+ if tempo.state_tempo == 'draft':
+ tempo.state_tempo = 'approval_sales'
+ template = self.env.ref('indoteknik_custom.mail_template_res_user_company_tempo_approved_by_sales')
+ template.send_mail(tempo.id, force_send=True)
+ elif tempo.state_tempo == 'approval_sales':
+ tempo.state_tempo = 'approval_finance'
+ template = self.env.ref('indoteknik_custom.mail_template_res_user_company_tempo_to_aprove_director')
+ template.send_mail(tempo.id, force_send=True)
+ elif tempo.state_tempo == 'approval_finance':
+ tempo.state_tempo = 'approval_director'
+
+
+
+class UserPengajuanTempoRequest(models.Model):
+ _name = 'user.pengajuan.tempo.request'
+ _inherit = ['mail.thread', 'mail.activity.mixin']
+ _rec_name = 'user_id'
+
+ user_id = fields.Many2one('res.partner', string='User')
+ user_company_id = fields.Many2one('res.partner', string='Company')
+ pengajuan_tempo_id = fields.Many2one('user.pengajuan.tempo', string='Form Tempo')
+ tempo_duration = fields.Many2one('account.payment.term', string='Durasi Tempo', tracking=3, domain=[('id', 'in', [24, 25, 29, 32])])
+ tempo_limit = fields.Integer(string='Limit Tempo', tracking=3)
+ state_tempo = fields.Selection([
+ ('draft', 'Pengajuan Tempo'),
+ ('approval_sales', 'Approved by Sales Manager'),
+ ('approval_finance', 'Approved by Finance'),
+ ('approval_director', 'Approved by Director'),
+ ('reject', 'Rejected'),
+ ], string='Status', readonly=True, copy=False, index=True, track_visibility='onchange', default='draft')
+ reason_reject = fields.Char(string='Limit Tempo')
+
+ # informasi perusahaan
+ name_tempo = fields.Many2one('res.partner', string='Nama Perusahaan', related='pengajuan_tempo_id.name_tempo', store=True, tracking=True, readonly=False)
+ industry_id_tempo = fields.Many2one('res.partner.industry', 'Customer Industry', related='pengajuan_tempo_id.industry_id_tempo',store=True, tracking=True, readonly=False)
+ street_tempo = fields.Char(string="Alamat Perusahaan", related='pengajuan_tempo_id.street_tempo', store=True, tracking=True, readonly=False)
+ state_id_tempo = fields.Many2one('res.country.state', string='State', related='pengajuan_tempo_id.state_id_tempo', store=True, tracking=True, readonly=False)
+ city_id_tempo = fields.Many2one('vit.kota', string='City', related='pengajuan_tempo_id.city_id_tempo', store=True, tracking=True, readonly=False)
+ zip_tempo = fields.Char(string="Zip", related='pengajuan_tempo_id.zip_tempo', store=True, tracking=True, readonly=False)
+ mobile_tempo = fields.Char(string="No. Telfon Perusahaan", related='pengajuan_tempo_id.mobile_tempo', store=True, tracking=True, readonly=False)
+ bank_name_tempo = fields.Char(string="Nama Bank", related='pengajuan_tempo_id.bank_name_tempo', store=True, tracking=True, readonly=False)
+ account_name_tempo = fields.Char(string="Nama Rekening", related='pengajuan_tempo_id.account_name_tempo', store=True, tracking=True, readonly=False)
+ account_number_tempo = fields.Char(string="Nomor Rekening Bank", related='pengajuan_tempo_id.account_number_tempo', store=True, tracking=True, readonly=False)
+ website_tempo = fields.Char(string='Website', related='pengajuan_tempo_id.website_tempo', store=True, tracking=True, readonly=False)
+ portal = fields.Boolean(string='Portal Website', related='pengajuan_tempo_id.portal', store=True, tracking=True, readonly=False)
+ estimasi_tempo = fields.Char(string='Estimasi Pembelian Pertahun', related='pengajuan_tempo_id.estimasi_tempo', store=True, tracking=True, readonly=False)
+ tempo_duration_origin = fields.Many2one('account.payment.term', string='Durasi Tempo', related='pengajuan_tempo_id.tempo_duration', store=True, tracking=True, readonly=False, domain=[('id', 'in', [24, 25, 29, 32])])
+ tempo_limit_origin = fields.Char(string='Limit Tempo', related='pengajuan_tempo_id.tempo_limit' , store=True, tracking=True, readonly=False)
+ category_produk_ids = fields.Many2many('product.public.category', string='Kategori Produk yang Digunakan', related='pengajuan_tempo_id.category_produk_ids', readonly=False)
+
+ # Kontak Perusahaan
+ direktur_name = fields.Char(string='Nama Lengkap Direktur', related='pengajuan_tempo_id.direktur_name', store=True, readonly=False)
+ direktur_mobile = fields.Char(string='No. Telpon Direktur', related='pengajuan_tempo_id.direktur_mobile', store=True, readonly=False)
+ direktur_email = fields.Char(string='Email Direktur', related='pengajuan_tempo_id.direktur_email', store=True, readonly=False)
+ purchasing_name = fields.Char(string='Nama Purchasing', related='pengajuan_tempo_id.purchasing_name', store=True, readonly=False)
+ purchasing_mobile = fields.Char(string='No. Telpon Purchasing', related='pengajuan_tempo_id.purchasing_mobile', store=True, readonly=False)
+ purchasing_email = fields.Char(string='Email Purchasing', related='pengajuan_tempo_id.purchasing_email', store=True, readonly=False)
+ finance_name = fields.Char(string='Nama Finance', related='pengajuan_tempo_id.finance_name', store=True, readonly=False)
+ finance_mobile = fields.Char(string='No. Telpon Finance', related='pengajuan_tempo_id.finance_mobile', store=True, readonly=False)
+ finance_email = fields.Char(string='Email Finance', related='pengajuan_tempo_id.finance_email', store=True, readonly=False)
+
+ # Pengiriman
+ pic_tittle = fields.Char(string='Tittle PIC Penerimaan Barang', related='pengajuan_tempo_id.pic_tittle', store=True, readonly=False)
+ pic_name = fields.Char(string='Nama PIC Penerimaan Barang', related='pengajuan_tempo_id.pic_name', store=True, readonly=False)
+ street_pengiriman = fields.Char(string="Alamat Perusahaan", related='pengajuan_tempo_id.street_pengiriman', store=True, readonly=False)
+ state_id_pengiriman = fields.Many2one('res.country.state', string='State', related='pengajuan_tempo_id.state_id_pengiriman', store=True, readonly=False)
+ city_id_pengiriman = fields.Many2one('vit.kota', string='City', related='pengajuan_tempo_id.city_id_pengiriman', store=True, readonly=False)
+ district_id_pengiriman = fields.Many2one('vit.kecamatan', string='Kecamatan',related='pengajuan_tempo_id.district_id_pengiriman', store=True, readonly=False)
+ subDistrict_id_pengiriman = fields.Many2one('vit.kelurahan', string='Kelurahan', related='pengajuan_tempo_id.subDistrict_id_pengiriman', store=True, readonly=False)
+ zip_pengiriman = fields.Char(string="Zip", related='pengajuan_tempo_id.zip_pengiriman', store=True, readonly=False)
+ invoice_pic_tittle = fields.Char(string='Tittle PIC Penerimaan Invoice', related='pengajuan_tempo_id.invoice_pic_tittle', store=True, readonly=False)
+ invoice_pic = fields.Char(string='Nama PIC Penerimaan Invoice', related='pengajuan_tempo_id.invoice_pic', store=True, readonly=False)
+ street_invoice = fields.Char(string="Alamat Perusahaan", related='pengajuan_tempo_id.street_invoice', store=True, readonly=False)
+ state_id_invoice = fields.Many2one('res.country.state', string='State', related='pengajuan_tempo_id.state_id_invoice', store=True, readonly=False)
+ city_id_invoice = fields.Many2one('vit.kota', string='City', related='pengajuan_tempo_id.city_id_invoice', store=True, readonly=False)
+ district_id_invoice = fields.Many2one('vit.kecamatan', string='Kecamatan', related='pengajuan_tempo_id.district_id_invoice', store=True, readonly=False)
+ subDistrict_id_invoice = fields.Many2one('vit.kelurahan', string='Kelurahan', related='pengajuan_tempo_id.subDistrict_id_invoice', store=True, readonly=False)
+ zip_invoice = fields.Char(string="Zip", related='pengajuan_tempo_id.zip_invoice', store=True, readonly=False)
+ tukar_invoice = fields.Char(string='Jadwal Penukaran Invoice', related='pengajuan_tempo_id.tukar_invoice', store=True, readonly=False)
+ jadwal_bayar = fields.Char(string='Jadwal Pembayaran', related='pengajuan_tempo_id.jadwal_bayar', store=True, readonly=False)
+ dokumen_pengiriman = fields.Char(string='Dokumen Tanda Terima yang Diberikan Pada Saat Pengiriman Barang', related='pengajuan_tempo_id.dokumen_pengiriman', store=True, readonly=False)
+ dokumen_pengiriman_input = fields.Char(string='Dokumen yang dibawa saat pengiriman barang', related='pengajuan_tempo_id.dokumen_pengiriman_input', store=True, readonly=False)
+ dokumen_invoice = fields.Char(string='Dokumen yang dilampirkan saat Pengiriman Invoice', related='pengajuan_tempo_id.dokumen_invoice', store=True, readonly=False)
+ is_same_address = fields.Boolean(string="Same Address pengiriman invoicr dan alamat pengiriman barang", related='pengajuan_tempo_id.is_same_address', store=True, readonly=False)
+ is_same_address_street = fields.Boolean(string="Same Address pengiriman barang dan alamat bisnis", related='pengajuan_tempo_id.is_same_address_street', store=True, readonly=False)
+
+ #Referensi
+ supplier_ids = fields.Many2many('user.pengajuan.tempo.line',related='pengajuan_tempo_id.supplier_ids', string="Suppliers", readonly=False)
+
+ # Dokumen
+ dokumen_npwp = fields.Many2many(
+ 'ir.attachment',
+ 'pengajuan_dokumen_npwp_rel',
+ string="NPWP Perusahaan",
+ related='pengajuan_tempo_id.dokumen_npwp',
+ readonly=False,
+ tracking=3
+ )
+
+ dokumen_sppkp = fields.Many2many(
+ 'ir.attachment',
+ 'pengajuan_dokumen_sppkp_rel',
+ string="SPPKP Perusahaan",
+ related='pengajuan_tempo_id.dokumen_sppkp',
+ readonly=False,
+ tracking=3
+ )
+ dokumen_nib = fields.Many2many(
+ 'ir.attachment',
+ 'pengajuan_dokumen_nib_rel',
+ string="NIB",
+ related='pengajuan_tempo_id.dokumen_nib',
+ readonly=False,
+ tracking=3,
+ track_visibility="onchange"
+ )
+ dokumen_siup = fields.Many2many(
+ 'ir.attachment',
+ 'pengajuan_dokumen_siup_rel',
+ string="SIUP",
+ related='pengajuan_tempo_id.dokumen_siup',
+ readonly=False,
+ tracking=3,
+ track_visibility="onchange"
+ )
+
+ dokumen_tdp = fields.Many2many(
+ 'ir.attachment',
+ 'pengajuan_dokumen_tdp_rel',
+ string="TDP",
+ related='pengajuan_tempo_id.dokumen_tdp',
+ readonly=False,
+ tracking=3,
+ track_visibility="onchange"
+ )
+ dokumen_skdp = fields.Many2many(
+ 'ir.attachment',
+ 'pengajuan_dokumen_skdp_rel',
+ string="SKDP",
+ related='pengajuan_tempo_id.dokumen_skdp',
+ readonly=False,
+ tracking=3,
+ track_visibility="onchange"
+ )
+
+ dokumen_skt = fields.Many2many(
+ 'ir.attachment',
+ 'pengajuan_dokumen_skt_rel',
+ string="SKT",
+ related='pengajuan_tempo_id.dokumen_skt',
+ readonly=False,
+ tracking=3,
+ track_visibility="onchange"
+ )
+
+ dokumen_akta_perubahan = fields.Many2many(
+ 'ir.attachment',
+ 'pengajuan_dokumen_akta_perubahan_rel',
+ string="Akta Perubahan",
+ related='pengajuan_tempo_id.dokumen_akta_perubahan',
+ readonly=False,
+ tracking=3
+ )
+
+ dokumen_ktp_dirut = fields.Many2many(
+ 'ir.attachment',
+ 'pengajuan_dokumen_ktp_dirut_rel',
+ string="KTP Dirut/Direktur",
+ related='pengajuan_tempo_id.dokumen_ktp_dirut',
+ readonly=False,
+ tracking=3
+ )
+
+ dokumen_akta_pendirian = fields.Many2many(
+ 'ir.attachment',
+ 'pengajuan_dokumen_angkta_pendirian_rel',
+ string="Akta Pendirian",
+ related='pengajuan_tempo_id.dokumen_akta_pendirian',
+ readonly=False,
+ tracking=3
+ )
+
+ dokumen_laporan_keuangan = fields.Many2many(
+ 'ir.attachment',
+ 'pengajuan_dokumen_laporan_keuangan_rel',
+ string="Laporan Keuangan",
+ related='pengajuan_tempo_id.dokumen_laporan_keuangan',
+ readonly=False,
+ tracking=3
+ )
+
+ dokumen_foto_kantor = fields.Many2many(
+ 'ir.attachment',
+ 'pengajuan_dokumen_foto_kantor_rel',
+ string="Foto Kantor (Tampak Depan)",
+ related='pengajuan_tempo_id.dokumen_foto_kantor',
+ readonly=False,
+ tracking=3
+ )
+
+ dokumen_tempat_bekerja = fields.Many2many(
+ 'ir.attachment',
+ 'pengajuan_dokumen_tempat_bekerja_rel',
+ string="Tempat Bekerja",
+ related='pengajuan_tempo_id.dokumen_tempat_bekerja',
+ readonly=False,
+ tracking=3
+ )
+
+ @api.onchange('name_tempo', 'industry_id_tempo', 'street_tempo', 'state_id_tempo', 'city_id_tempo', 'zip_tempo',
+ 'mobile_tempo', 'bank_name_tempo', 'account_name_tempo', 'account_number_tempo', 'website_tempo',
+ 'estimasi_tempo', 'tempo_duration_origin', 'tempo_limit_origin', 'category_produk_ids')
+ def _onchange_related_fields(self):
+ if self.pengajuan_tempo_id:
+ # Perbarui nilai di pengajuan_tempo_id
+ self.pengajuan_tempo_id.name_tempo = self.name_tempo
+ self.pengajuan_tempo_id.industry_id_tempo = self.industry_id_tempo
+ self.pengajuan_tempo_id.street_tempo = self.street_tempo
+ self.pengajuan_tempo_id.state_id_tempo = self.state_id_tempo
+ self.pengajuan_tempo_id.city_id_tempo = self.city_id_tempo
+ self.pengajuan_tempo_id.zip_tempo = self.zip_tempo
+ self.pengajuan_tempo_id.mobile_tempo = self.mobile_tempo
+ self.pengajuan_tempo_id.bank_name_tempo = self.bank_name_tempo
+ self.pengajuan_tempo_id.account_name_tempo = self.account_name_tempo
+ self.pengajuan_tempo_id.account_number_tempo = self.account_number_tempo
+ self.pengajuan_tempo_id.website_tempo = self.website_tempo
+ self.pengajuan_tempo_id.portal = self.portal
+ self.pengajuan_tempo_id.estimasi_tempo = self.estimasi_tempo
+ self.pengajuan_tempo_id.tempo_duration = self.tempo_duration_origin
+ self.pengajuan_tempo_id.tempo_limit = self.tempo_limit_origin
+ self.pengajuan_tempo_id.category_produk_ids = self.category_produk_ids
+
+ @api.onchange('direktur_name', 'direktur_mobile', 'direktur_email', 'purchasing_name', 'purchasing_mobile',
+ 'purchasing_email', 'finance_name', 'finance_mobile', 'finance_email')
+ def _onchange_related_fields_kontak(self):
+ if self.pengajuan_tempo_id:
+ # Perbarui nilai di pengajuan_tempo_id
+ self.pengajuan_tempo_id.direktur_name = self.direktur_name
+ self.pengajuan_tempo_id.direktur_mobile = self.direktur_mobile
+ self.pengajuan_tempo_id.direktur_email = self.direktur_email
+ self.pengajuan_tempo_id.purchasing_name = self.purchasing_name
+ self.pengajuan_tempo_id.purchasing_mobile = self.purchasing_mobile
+ self.pengajuan_tempo_id.purchasing_email = self.purchasing_email
+ self.pengajuan_tempo_id.finance_name = self.finance_name
+ self.pengajuan_tempo_id.finance_mobile = self.finance_mobile
+ self.pengajuan_tempo_id.finance_email = self.finance_email
+
+ @api.onchange('pic_tittle', 'pic_name', 'street_pengiriman', 'state_id_pengiriman', 'city_id_pengiriman',
+ 'zip_pengiriman', 'district_id_pengiriman', 'subDistrict_id_pengiriman'
+ 'invoice_pic_tittle', 'invoice_pic', 'street_invoice', 'state_id_invoice', 'city_id_invoice',
+ 'district_id_invoice', 'subDistrict_id_invoice', 'zip_invoice',
+ 'tukar_invoice', 'jadwal_bayar', 'dokumen_pengiriman', 'dokumen_pengiriman_input', 'dokumen_invoice',
+ 'is_same_address', 'is_same_address_street')
+ def _onchange_related_fields_pengiriman(self):
+ if self.pengajuan_tempo_id:
+ # Perbarui nilai di pengajuan_tempo_id
+ self.pengajuan_tempo_id.pic_tittle = self.pic_tittle
+ self.pengajuan_tempo_id.pic_name = self.pic_name
+ self.pengajuan_tempo_id.street_pengiriman = self.street_pengiriman
+ self.pengajuan_tempo_id.state_id_pengiriman = self.state_id_pengiriman
+ self.pengajuan_tempo_id.city_id_pengiriman = self.city_id_pengiriman
+ self.pengajuan_tempo_id.district_id_pengiriman = self.district_id_pengiriman
+ self.pengajuan_tempo_id.subDistrict_id_pengiriman = self.subDistrict_id_pengiriman
+ self.pengajuan_tempo_id.zip_pengiriman = self.zip_pengiriman
+ self.pengajuan_tempo_id.invoice_pic_tittle = self.invoice_pic_tittle
+ self.pengajuan_tempo_id.invoice_pic = self.invoice_pic
+ self.pengajuan_tempo_id.street_invoice = self.street_invoice
+ self.pengajuan_tempo_id.state_id_invoice = self.state_id_invoice
+ self.pengajuan_tempo_id.city_id_invoice = self.city_id_invoice
+ self.pengajuan_tempo_id.district_id_invoice = self.district_id_invoice
+ self.pengajuan_tempo_id.subDistrict_id_invoice = self.subDistrict_id_invoice
+ self.pengajuan_tempo_id.zip_invoice = self.zip_invoice
+ self.pengajuan_tempo_id.tukar_invoice = self.tukar_invoice
+ self.pengajuan_tempo_id.jadwal_bayar = self.jadwal_bayar
+ self.pengajuan_tempo_id.dokumen_pengiriman = self.dokumen_pengiriman
+ self.pengajuan_tempo_id.dokumen_pengiriman_input = self.dokumen_pengiriman_input
+ self.pengajuan_tempo_id.dokumen_invoice = self.dokumen_invoice
+ self.pengajuan_tempo_id.is_same_address = self.is_same_address
+ self.pengajuan_tempo_id.is_same_address_street = self.is_same_address_street
+
+ @api.onchange('supplier_ids')
+ def _onchange_supplier_ids(self):
+ if self.pengajuan_tempo_id:
+ self.pengajuan_tempo_id.supplier_ids = self.supplier_ids
+
+ @api.onchange('dokumen_nib', 'dokumen_npwp', 'dokumen_sppkp', 'dokumen_akta_perubahan',
+ 'dokumen_ktp_dirut', 'dokumen_akta_pendirian', 'dokumen_laporan_keuangan',
+ 'dokumen_foto_kantor', 'dokumen_tempat_bekerja', 'dokumen_skdp', 'dokumen_skt', 'dokumen_siup',
+ 'dokumen_tdp')
+ def _onchange_related_fields_dokumen(self):
+ if self.pengajuan_tempo_id:
+ # Perbarui nilai di pengajuan_tempo_id
+ self.pengajuan_tempo_id.dokumen_nib = self.dokumen_nib
+ self.pengajuan_tempo_id.dokumen_siup = self.dokumen_siup
+ self.pengajuan_tempo_id.dokumen_tdp = self.dokumen_tdp
+ self.pengajuan_tempo_id.dokumen_skdp = self.dokumen_skdp
+ self.pengajuan_tempo_id.dokumen_skt = self.dokumen_skt
+ self.pengajuan_tempo_id.dokumen_npwp = self.dokumen_npwp
+ self.pengajuan_tempo_id.dokumen_sppkp = self.dokumen_sppkp
+ self.pengajuan_tempo_id.dokumen_akta_perubahan = self.dokumen_akta_perubahan
+ self.pengajuan_tempo_id.dokumen_ktp_dirut = self.dokumen_ktp_dirut
+ self.pengajuan_tempo_id.dokumen_akta_pendirian = self.dokumen_akta_pendirian
+ self.pengajuan_tempo_id.dokumen_laporan_keuangan = self.dokumen_laporan_keuangan
+ self.pengajuan_tempo_id.dokumen_foto_kantor = self.dokumen_foto_kantor
+ self.pengajuan_tempo_id.dokumen_tempat_bekerja = self.dokumen_tempat_bekerja
+
+ @api.onchange('tempo_duration')
+ def _tempo_duration_change(self):
+ for tempo in self:
+ if tempo.env.user.id not in (7, 377, 12182):
+ raise UserError("Durasi tempo hanya bisa di ubah oleh Sales Manager atau Direktur")
+
+ @api.onchange('tempo_limit')
+ def _onchange_tempo_limit(self):
+ for tempo in self:
+ if tempo.env.user.id not in (7, 377, 12182):
+ raise UserError("Limit tempo hanya bisa diubah oleh Sales Manager atau Direktur")
+ def button_approve(self):
+ for tempo in self:
+ if not self.tempo_limit:
+ raise UserError("Limit Tempo harus di isi terlebih dahulu")
+ if tempo.state_tempo == 'draft':
+ if tempo.env.user.id in (688, 28, 7):
+ raise UserError("Pengajuan tempo harus di approve oleh sales manager terlebih dahulu")
+ else:
+ if tempo.env.user.id not in (377, 12182):
+ # if tempo.env.user.id != 12182:
+ raise UserError("Pengajuan tempo hanya bisa di approve oleh sales manager")
+ else:
+ return {
+ 'type': 'ir.actions.act_window',
+ 'name': 'Konfirmasi Approve',
+ 'res_model': 'confirm.approval.wizard',
+ 'view_mode': 'form',
+ 'target': 'new',
+ 'context': {
+ 'default_tempo_id': tempo.id,
+ },
+ }
+
+ elif tempo.state_tempo == 'approval_sales':
+ if tempo.env.user.id == 7:
+ raise UserError("Pengajuan tempo harus di approve oleh Finence terlebih dahulu")
+ else:
+ if tempo.env.user.id not in (688, 28, 12182):
+ # if tempo.env.user.id not in (288,28,12182):
+ raise UserError("Pengajuan tempo hanya bisa di approve oleh Finence")
+ else:
+ return {
+ 'type': 'ir.actions.act_window',
+ 'name': 'Konfirmasi Approve',
+ 'res_model': 'confirm.approval.wizard',
+ 'view_mode': 'form',
+ 'target': 'new',
+ 'context': {
+ 'default_tempo_id': tempo.id,
+ },
+ }
+
+ elif tempo.state_tempo == 'approval_finance':
+ if tempo.env.user.id != 7:
+ # if tempo.env.user.id != 12182:
+ raise UserError("Pengajuan tempo hanya bisa di approve oleh Direktur")
+ else:
+ return {
+ 'type': 'ir.actions.act_window',
+ 'name': 'Konfirmasi Approve',
+ 'res_model': 'confirm.approval.wizard',
+ 'view_mode': 'form',
+ 'target': 'new',
+ 'context': {
+ 'default_tempo_id': tempo.id,
+ },
+ }
+
+ def button_reject(self):
+ return {
+ 'type': 'ir.actions.act_window',
+ 'name': _('Reject Reason'),
+ 'res_model': 'reject.reason.wizard',
+ 'view_mode': 'form',
+ 'target': 'new',
+ 'context': {'default_request_id': self.id},
+ }
+
+ def write(self, vals):
+ is_approve = True if self.state_tempo == 'approval_director' or vals.get('state_tempo') == 'approval_director' else False
+ # if self.is_approve and is_approve:
+ # raise UserError('Tidak dapat mengubah approval yang sudah diisi')
+ limit_tempo = ''
+ if vals.get('tempo_limit'):
+ limit_tempo = vals.get('tempo_limit')
+ elif self.tempo_limit:
+ limit_tempo = self.tempo_limit
+ else:
+ limit_tempo = self.pengajuan_tempo_id.tempo_limit
+
+ tempo_duration = ''
+ if vals.get('tempo_duration'):
+ tempo_duration = vals.get('tempo_duration')
+ elif self.tempo_duration:
+ tempo_duration = self.tempo_duration
+ else:
+ tempo_duration = self.pengajuan_tempo_id.tempo_duration
+ if is_approve:
+ self.pengajuan_tempo_id.partner_id = self.user_id.id
+ # informasi perusahaan
+ self.user_company_id.name_tempo = self.pengajuan_tempo_id.name_tempo
+ self.user_company_id.industry_id_tempo = self.pengajuan_tempo_id.industry_id_tempo
+ self.user_company_id.street_tempo = self.pengajuan_tempo_id.street_tempo
+ self.user_company_id.state_id_tempo = self.pengajuan_tempo_id.state_id_tempo
+ self.user_company_id.city_id_tempo = self.pengajuan_tempo_id.city_id_tempo
+ self.user_company_id.zip_tempo = self.pengajuan_tempo_id.zip_tempo
+ self.user_company_id.mobile_tempo = self.pengajuan_tempo_id.mobile_tempo
+ self.user_company_id.bank_name_tempo = self.pengajuan_tempo_id.bank_name_tempo
+ self.user_company_id.account_name_tempo = self.pengajuan_tempo_id.account_name_tempo
+ self.user_company_id.account_number_tempo = self.pengajuan_tempo_id.account_number_tempo
+ self.user_company_id.website_tempo = self.pengajuan_tempo_id.website_tempo
+ self.user_company_id.portal = self.pengajuan_tempo_id.portal
+ self.user_company_id.estimasi_tempo = self.pengajuan_tempo_id.estimasi_tempo
+ self.user_company_id.tempo_duration = tempo_duration.id
+ self.user_company_id.tempo_limit = limit_tempo
+ self.user_company_id.category_produk_ids = self.pengajuan_tempo_id.category_produk_ids
+
+ # Kontak Perusahaan
+ self.user_company_id.direktur_name = self.pengajuan_tempo_id.direktur_name
+ self.user_company_id.direktur_mobile = self.pengajuan_tempo_id.direktur_mobile
+ self.user_company_id.direktur_email = self.pengajuan_tempo_id.direktur_email
+ self.user_company_id.purchasing_name = self.pengajuan_tempo_id.purchasing_name
+ self.user_company_id.purchasing_mobile = self.pengajuan_tempo_id.purchasing_mobile
+ self.user_company_id.purchasing_email = self.pengajuan_tempo_id.purchasing_email
+ self.user_company_id.finance_name = self.pengajuan_tempo_id.finance_name
+ self.user_company_id.finance_mobile = self.pengajuan_tempo_id.finance_mobile
+ self.user_company_id.finance_email = self.pengajuan_tempo_id.finance_email
+
+ # Data untuk kontak baru
+ contacts_data = [
+ {
+ "type": "contact",
+ 'title': 6 if self.pengajuan_tempo_id.direktur_tittle == 'Bpk' else 7,
+ "name": self.pengajuan_tempo_id.direktur_name,
+ "email": self.pengajuan_tempo_id.direktur_email,
+ "phone": self.pengajuan_tempo_id.direktur_mobile,
+ },
+ {
+ "type": "contact",
+ 'title': 6 if self.pengajuan_tempo_id.purchasing_tittle == 'Bpk' else 7,
+ "name": self.pengajuan_tempo_id.purchasing_name,
+ "email": self.pengajuan_tempo_id.purchasing_email,
+ "phone": self.pengajuan_tempo_id.purchasing_mobile,
+ },
+ {
+ "type": "contact",
+ 'title': 6 if self.pengajuan_tempo_id.finance_tittle == 'Bpk' else 7,
+ "name": self.pengajuan_tempo_id.finance_name,
+ "email": self.pengajuan_tempo_id.finance_email,
+ "phone": self.pengajuan_tempo_id.finance_mobile,
+ },
+ {
+ "type": "delivery",
+ "name": self.pengajuan_tempo_id.pic_name,
+ "street": self.pengajuan_tempo_id.street_pengiriman,
+ "state_id": self.pengajuan_tempo_id.state_id_pengiriman.id,
+ "kota_id": self.pengajuan_tempo_id.city_id_pengiriman.id,
+ "kecamatan_id": self.pengajuan_tempo_id.district_id_pengiriman.id,
+ "kelurahan_id": self.pengajuan_tempo_id.subDistrict_id_pengiriman.id,
+ "zip": self.pengajuan_tempo_id.zip_pengiriman,
+ },
+ {
+ "type": "invoice",
+ "name": self.pengajuan_tempo_id.invoice_pic,
+ "street": self.pengajuan_tempo_id.street_invoice,
+ "state_id": self.pengajuan_tempo_id.state_id_invoice.id,
+ "kota_id": self.pengajuan_tempo_id.city_id_invoice.id,
+ "kecamatan_id": self.pengajuan_tempo_id.district_id_invoice.id,
+ "kelurahan_id": self.pengajuan_tempo_id.subDistrict_id_invoice.id,
+ "zip": self.pengajuan_tempo_id.zip_invoice,
+ },
+ ]
+
+ # Buat kontak baru untuk company_id
+ for contact_data in contacts_data:
+ self.env['res.partner'].create({
+ "parent_id": self.user_company_id.id, # Hubungkan ke perusahaan
+ **contact_data, # Tambahkan data kontak
+ })
+
+ # Pengiriman
+ self.user_company_id.pic_name = self.pengajuan_tempo_id.pic_name
+ self.user_company_id.street_pengiriman = self.pengajuan_tempo_id.street_pengiriman
+ self.user_company_id.state_id_pengiriman = self.pengajuan_tempo_id.state_id_pengiriman
+ self.user_company_id.city_id_pengiriman = self.pengajuan_tempo_id.city_id_pengiriman
+ self.user_company_id.district_id_pengiriman = self.pengajuan_tempo_id.district_id_pengiriman
+ self.user_company_id.subDistrict_id_pengiriman = self.pengajuan_tempo_id.subDistrict_id_pengiriman
+ self.user_company_id.zip_pengiriman = self.pengajuan_tempo_id.zip_pengiriman
+ self.user_company_id.invoice_pic = self.pengajuan_tempo_id.invoice_pic
+ self.user_company_id.street_invoice = self.pengajuan_tempo_id.street_invoice
+ self.user_company_id.state_id_invoice = self.pengajuan_tempo_id.state_id_invoice
+ self.user_company_id.city_id_invoice = self.pengajuan_tempo_id.city_id_invoice
+ self.user_company_id.district_id_invoice = self.pengajuan_tempo_id.district_id_invoice
+ self.user_company_id.subDistrict_id_invoice = self.pengajuan_tempo_id.subDistrict_id_invoice
+ self.user_company_id.zip_invoice = self.pengajuan_tempo_id.zip_invoice
+ self.user_company_id.tukar_invoice = self.pengajuan_tempo_id.tukar_invoice
+ self.user_company_id.jadwal_bayar = self.pengajuan_tempo_id.jadwal_bayar
+ self.user_company_id.dokumen_pengiriman = self.pengajuan_tempo_id.dokumen_pengiriman
+ self.user_company_id.dokumen_pengiriman_input = self.pengajuan_tempo_id.dokumen_pengiriman_input
+ self.user_company_id.dokumen_invoice = self.pengajuan_tempo_id.dokumen_invoice
+
+ # Referensi
+ self.user_company_id.supplier_ids = self.pengajuan_tempo_id.supplier_ids
+
+ # Dokumen
+ self.user_company_id.dokumen_npwp = self.pengajuan_tempo_id.dokumen_npwp[0] if self.pengajuan_tempo_id.dokumen_npwp else []
+ if self.user_company_id.dokumen_npwp:
+ self.user_company_id.message_post(body='Dokumen NPWP', attachment_ids=[self.user_company_id.dokumen_npwp.id])
+
+ self.user_company_id.dokumen_sppkp = self.pengajuan_tempo_id.dokumen_sppkp[0] if self.pengajuan_tempo_id.dokumen_sppkp else []
+ if self.user_company_id.dokumen_sppkp:
+ self.user_company_id.message_post(body='Dokumen SPPKP', attachment_ids=[self.user_company_id.dokumen_sppkp.id])
+
+ self.user_company_id.dokumen_nib = self.pengajuan_tempo_id.dokumen_nib[0] if self.pengajuan_tempo_id.dokumen_nib else []
+ if self.user_company_id.dokumen_nib:
+ self.user_company_id.message_post(body='Dokumen NIB', attachment_ids=[self.user_company_id.dokumen_nib.id])
+
+ self.user_company_id.dokumen_siup = self.pengajuan_tempo_id.dokumen_siup[0] if self.pengajuan_tempo_id.dokumen_siup else []
+ if self.user_company_id.dokumen_siup:
+ self.user_company_id.message_post(body='dokumen SIUP', attachment_ids=[self.user_company_id.dokumen_siup.id])
+
+ self.user_company_id.dokumen_tdp = self.pengajuan_tempo_id.dokumen_tdp[0] if self.pengajuan_tempo_id.dokumen_tdp else []
+ if self.user_company_id.dokumen_tdp:
+ self.user_company_id.message_post(body='dokumen TDP', attachment_ids=[self.user_company_id.dokumen_tdp.id])
+
+ self.user_company_id.dokumen_skdp = self.pengajuan_tempo_id.dokumen_skdp[0] if self.pengajuan_tempo_id.dokumen_skdp else []
+ if self.user_company_id.dokumen_skdp:
+ self.user_company_id.message_post(body='dokumen SKDP', attachment_ids=[self.user_company_id.dokumen_skdp.id])
+
+ self.user_company_id.dokumen_skt = self.pengajuan_tempo_id.dokumen_skt[0] if self.pengajuan_tempo_id.dokumen_skt else []
+ if self.user_company_id.dokumen_skt:
+ self.user_company_id.message_post(body='dokumen SKT', attachment_ids=[self.user_company_id.dokumen_skt.id])
+
+ self.user_company_id.dokumen_akta_perubahan = self.pengajuan_tempo_id.dokumen_akta_perubahan[0] if self.pengajuan_tempo_id.dokumen_akta_perubahan else []
+ if self.user_company_id.dokumen_akta_perubahan:
+ self.user_company_id.message_post(body='Dokumen Akta Perubahan',
+ attachment_ids=[self.user_company_id.dokumen_akta_perubahan.id])
+
+ self.user_company_id.dokumen_ktp_dirut = self.pengajuan_tempo_id.dokumen_ktp_dirut[0] if self.pengajuan_tempo_id.dokumen_ktp_dirut else []
+ if self.user_company_id.dokumen_ktp_dirut:
+ self.user_company_id.message_post(body='Dokumen Ktp Dirut',
+ attachment_ids=[self.user_company_id.dokumen_ktp_dirut.id])
+
+ self.user_company_id.dokumen_akta_pendirian = self.pengajuan_tempo_id.dokumen_akta_pendirian[0] if self.pengajuan_tempo_id.dokumen_akta_pendirian else []
+ if self.user_company_id.dokumen_akta_pendirian:
+ self.user_company_id.message_post(body='Dokumen Akta Pendirian',
+ attachment_ids=[self.user_company_id.dokumen_akta_pendirian.id])
+
+ self.user_company_id.dokumen_laporan_keuangan = self.pengajuan_tempo_id.dokumen_laporan_keuangan[0] if self.pengajuan_tempo_id.dokumen_laporan_keuangan else []
+ if self.user_company_id.dokumen_laporan_keuangan:
+ self.user_company_id.message_post(body='Dokumen Laporan Keuangan',
+ attachment_ids=[self.user_company_id.dokumen_laporan_keuangan.id])
+
+ self.user_company_id.dokumen_foto_kantor = self.pengajuan_tempo_id.dokumen_foto_kantor[0] if self.pengajuan_tempo_id.dokumen_foto_kantor else []
+ if self.user_company_id.dokumen_foto_kantor:
+ self.user_company_id.message_post(body='Dokumen Foto Kantor',
+ attachment_ids=[self.user_company_id.dokumen_foto_kantor.id])
+
+ self.user_company_id.dokumen_tempat_bekerja = self.pengajuan_tempo_id.dokumen_tempat_bekerja[0] if self.pengajuan_tempo_id.dokumen_tempat_bekerja else []
+ if self.user_company_id.dokumen_tempat_bekerja:
+ self.user_company_id.message_post(body='Dokumen Tempat Bekerja',
+ attachment_ids=[self.user_company_id.dokumen_tempat_bekerja.id])
+ # self.user_company_id.active = True
+ # user.send_company_request_approve_mail()
+ self.user_company_id.property_payment_term_id = self.pengajuan_tempo_id.tempo_duration.id
+ self.user_company_id.active_limit = True
+ self.user_company_id.warning_stage = float(limit_tempo) - (float(limit_tempo)/2)
+ self.user_company_id.blocking_stage = limit_tempo
+
+ # Internal Notes
+ comment = []
+ if self.pengajuan_tempo_id.tukar_invoice:
+ comment.append(f"Jadwal Tukar Invoice: {self.pengajuan_tempo_id.tukar_invoice}")
+ if self.pengajuan_tempo_id.jadwal_bayar:
+ comment.append(f"Jadwal Pembayaran: {self.pengajuan_tempo_id.jadwal_bayar}")
+ self.user_company_id.comment = "\n".join(comment)
+
+
+ # template = self.env.ref('indoteknik_custom.mail_template_res_user_company_tempo_approved')
+ # tempo = self.pengajuan_tempo_id
+ # template.send_mail(tempo.id, force_send=True)
+ template = self.env.ref('indoteknik_custom.mail_template_res_user_company_tempo_approved')
+ template.send_mail(self.id, force_send=True)
+ # self.user_id.parent_id = new_company.id
+ # user.send_company_request_reject_mail()
+ return super(UserPengajuanTempoRequest, self).write(vals)
+
+ def get_user_by_email(self, email):
+ return request.env['res.users'].search([
+ ('login', '=', email),
+ ('active', 'in', [True, False])
+ ])
+
+ def format_currency(self, number):
+ number = int(number)
+ return "{:,}".format(number).replace(',', '.') \ No newline at end of file
diff --git a/indoteknik_custom/models/website_telegram.py b/indoteknik_custom/models/website_telegram.py
new file mode 100644
index 00000000..c877a067
--- /dev/null
+++ b/indoteknik_custom/models/website_telegram.py
@@ -0,0 +1,193 @@
+import requests
+# import clipboard
+from odoo import models, fields, api
+from telethon.sessions import StringSession
+from telethon.sync import TelegramClient
+from odoo.exceptions import UserError
+from telethon import functions, types
+from telethon.tl.types import InputPeerChannel
+import asyncio
+from telethon.tl.functions.messages import SendMessageRequest
+# from telethon.tl.types import InputMediaPoll, Poll, PollAnswer, PeerChannel
+import datetime
+from telethon.tl.types import MessageMediaPoll
+# from telethon.tl.functions.messages import SendMediaRequest
+# from telethon.tl.types import TextWithEntities
+
+class WebsiteTelegram(models.Model):
+ _name = 'website.telegram'
+ _description = 'Telegram Channel'
+
+
+ tittle = fields.Char("Channel Title")
+ invite_link = fields.Char("Channel invite link")
+ username = fields.Char("Channel Name")
+ user_id = fields.Many2many('res.partner', string='User Member', store=True)
+ id_data = fields.Char("Channel ID")
+ about = fields.Char("Channel Description")
+ is_broadcast = fields.Boolean("Is Broadcast", default=True)
+ is_megagroup = fields.Boolean("Is Megagroup", default=False)
+ is_accept = fields.Boolean("Is Megagroup", default=False)
+
+ # session_string = 'MIIBCgKCAQEAyMEdY1aR+sCR3ZSJrtztKTKqigvO/vBfqACJLZtS7QMgCGXJ6XIRyy7mx66W0/sOFa7/1mAZtEoIokDP3ShoqF4fVNb6XeqgQfaUHd8wJpDWHcR2OFwvplUUI1PLTktZ9uW2WE23b+ixNwJjJGwBDJPQEQFBE+vfmH0JP503wr5INS1poWg/j25sIWeYPHYeOrFp/eXaqhISP6G+q2IeTaWTXpwZj4LzXq5YOpk4bYEQ6mvRq7D1aHWfYmlEGepfaYR8Q0YqvvhYtMte3ITnuSJs171+GDqpdKcSwHnd6FudwGO4pcCOj4WcDuXc2CTHgH8gFTNhp/Y8/SpDOhvn9QIDAQAB'
+
+
+ def create_channel(self, message):
+ asyncio.run(self._async_create_channel(message))
+
+ async def _async_create_channel(self, message):
+ async with TelegramClient(StringSession(
+ '1BVtsOJABu30MWCBFwYvvaYbFoIWi43r5a7TUZ2IWwrnSlXIwEhJS5k2y4UKjoDeMPKwhgUWn9lMk02zQjM0ZDzq61YyhkRBvZuu3hCxMsrtP92bkuZtL2g3g1VgI8s7rMhOD_WaGrZbuj-TmbTwIEbN5i1J4raDW2kYzmlLRCbT74xxrGjpzWCnVv7CSS9L2juXuut0lLMgli3_JZbqDO1IyBYh4ZFQYbMf7zv6moDR4MQp1qfnFArsikQcfxjlNXKFcSoyA_GjiIFfCuymwQVtdERXOAH03M_lm8fYbjvgxEkJvxR6hdCnYMcKpIujEEo9SmMmK7Vnl29g1TCPO5tlrDNXq3Ng='),
+ 27799517, 'df8ee44b0ed11108245037d47b511201') as client:
+ result = await client(functions.channels.CreateChannelRequest(
+ title=self.tittle,
+ about=self.about,
+ broadcast=False,
+ megagroup=True,
+ ))
+ channel = result.updates[3].message.peer_id
+ channel_link = await client(functions.messages.ExportChatInviteRequest(
+ peer=InputPeerChannel(channel_id=channel.channel_id, access_hash=result.chats[0].access_hash),
+ ))
+ self.invite_link = channel_link.link
+
+ # Iterasi untuk setiap username
+ for name in self.user_id:
+ if name.telegram_id:
+ user_to_add = await client.get_entity(name.telegram_id)
+ result_add_user = await client(functions.channels.InviteToChannelRequest(
+ channel=channel,
+ users=[user_to_add.id],
+ ))
+ else:
+ raise UserError('ID Telegram '+ name.name + ' salah atau belum diisi')
+ # message = 'https://erp.indoteknik.com/web#id=' + self.id_data + '&action=209&model=sale.order&view_type=form&cids=1&menu_id=101'
+ message_template = 'https://erp.indoteknik.com/web#id=' + self.id_data + '&action=357&model=sale.order&view_type=form&cids=1&menu_id=212'
+ message2 = self.tittle + ' di print oleh ' + self.env.user.name
+ result_massage = await client(SendMessageRequest(channel, message_template))
+ result_massage2 = await client(SendMessageRequest(channel, message))
+
+ # Send the poll to the channel using PeerChannel with the channel's ID
+ # result_polling = await client(SendMediaRequest(
+ # peer=InputPeerChannel(channel_id=channel.channel_id, access_hash=result.chats[0].access_hash),
+ # media=InputMediaPoll(poll=Poll(
+ # question=TextWithEntities(text="ASK RETURN?", entities=[]),
+ # answers=[
+ # PollAnswer(text=TextWithEntities(text="Accept", entities=[]), option=b'\x01'),
+ # PollAnswer(text=TextWithEntities(text="Reject", entities=[]), option=b'\x02'),
+ # ],
+ # id=2
+ # )),
+ # message='Ask Return Polling'
+ # ))
+
+ def receive_messages(self):
+ return asyncio.run(self._async_receive_messages())
+
+ async def _async_receive_messages(self):
+ async with TelegramClient(StringSession(
+ '1BVtsOJABu30MWCBFwYvvaYbFoIWi43r5a7TUZ2IWwrnSlXIwEhJS5k2y4UKjoDeMPKwhgUWn9lMk02zQjM0ZDzq61YyhkRBvZuu3hCxMsrtP92bkuZtL2g3g1VgI8s7rMhOD_WaGrZbuj-TmbTwIEbN5i1J4raDW2kYzmlLRCbT74xxrGjpzWCnVv7CSS9L2juXuut0lLMgli3_JZbqDO1IyBYh4ZFQYbMf7zv6moDR4MQp1qfnFArsikQcfxjlNXKFcSoyA_GjiIFfCuymwQVtdERXOAH03M_lm8fYbjvgxEkJvxR6hdCnYMcKpIujEEo9SmMmK7Vnl29g1TCPO5tlrDNXq3Ng='),
+ 27799517, 'df8ee44b0ed11108245037d47b511201') as client:
+ channel = await client.get_entity(self.invite_link)
+ result = await client(functions.messages.GetHistoryRequest(
+ peer=channel,
+ offset_id=42,
+ offset_date=datetime.datetime(2024, 12, 31),
+ add_offset=0,
+ limit=100,
+ max_id=0,
+ min_id=0,
+ hash=channel.access_hash
+ ))
+ accept_found = False
+
+ for message in result.messages:
+ if not isinstance(message.media, MessageMediaPoll):
+ continue
+ if message.media.results.total_voters > 0:
+ if message.media.results.results[0].voters > message.media.results.results[1].voters:
+ accept_found = True
+ break
+
+ return accept_found
+
+ def send_to_telegram(self, message):
+ # apiURL = f'https://api.telegram.org/bot{self.bot_name}/sendMessage'
+ try:
+ # requests.post(apiURL, json={'chat_id': self.chatID, 'text': message})
+ asyncio.run(self._async_send_to_telegram(message))
+ except Exception as e:
+ print(e)
+
+ async def _async_send_to_telegram(self, message):
+ async with TelegramClient(StringSession(
+ '1BVtsOJABu30MWCBFwYvvaYbFoIWi43r5a7TUZ2IWwrnSlXIwEhJS5k2y4UKjoDeMPKwhgUWn9lMk02zQjM0ZDzq61YyhkRBvZuu3hCxMsrtP92bkuZtL2g3g1VgI8s7rMhOD_WaGrZbuj-TmbTwIEbN5i1J4raDW2kYzmlLRCbT74xxrGjpzWCnVv7CSS9L2juXuut0lLMgli3_JZbqDO1IyBYh4ZFQYbMf7zv6moDR4MQp1qfnFArsikQcfxjlNXKFcSoyA_GjiIFfCuymwQVtdERXOAH03M_lm8fYbjvgxEkJvxR6hdCnYMcKpIujEEo9SmMmK7Vnl29g1TCPO5tlrDNXq3Ng='),
+ 27799517, 'df8ee44b0ed11108245037d47b511201') as client:
+ channel = await client.get_entity(self.invite_link)
+
+ # Iterasi untuk setiap username
+ for username in self.user_id:
+ if username:
+ try:
+ user_to_add = await client.get_entity(username.telegram_id)
+
+ result_add_user = await client(functions.channels.InviteToChannelRequest(
+ channel=channel,
+ users=[user_to_add.id],
+ ))
+ except Exception as e:
+ print(f"Error adding user {username}: {e}")
+
+ result_message = await client(SendMessageRequest(channel, message))
+
+ def test_send(self):
+ try:
+ self.env.cr.savepoint()
+
+ self.env['website.telegram'].search([('tittle', '=', self.tittle)])[0].send_to_telegram('test message')
+ except Exception as e:
+ print(e)
+
+ # @api.depends('name', 'chatID', 'bot_name')
+ # def _calc_python_code(self):
+ # for record in self:
+ # if not record.name:
+ # record.python_code = "pleas put a name"
+ # elif not record.test_message:
+ # record.test_message = "test"
+ # else:
+ # record.python_code = "self.env['website.telegram'].search([('name', '=', '" + record.name + "')])[0].send_to_telegram('" + record.test_message + "')"
+ #
+ # def copy_chat_id(self):
+ # record = self.browse(self.id)
+ # clipboard.copy(record.python_code)
+ #
+ # def paste_chat_id(self):
+ # record = self.browse(self.id)
+ # chat_id = clipboard.paste()
+ # record.write({'chatID': chat_id})
+ #
+ # def paste_bot_name(self):
+ # record = self.browse(self.id)
+ # bot_name = clipboard.paste()
+ # record.write({'bot_name': bot_name})
+ #
+ # def get_updates(self):
+ # apiURL = f'https://api.telegram.org/bot{self.bot_name}/getUpdates'
+ # try:
+ # response = requests.get(apiURL)
+ # updates = response.json()
+ # return updates
+ # except Exception as e:
+ # print(e)
+ # return None
+
+ # def receive_messages(self):
+ # updates = self.get_updates()
+ # if updates and 'result' in updates:
+ # for update in updates['result']:
+ # if 'text' in update['channel_post']:
+ # message_text = update['channel_post']['text']
+ # chat_id = update['channel_post']['chat']['id']
+ # chat_name = update['channel_post']['chat']['username']
+ # print(f"Received message: {message_text} from chat_id: {chat_id}, that is: {chat_name}")