summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAzka Nathan <darizkyfaz@gmail.com>2025-03-05 14:02:13 +0700
committerAzka Nathan <darizkyfaz@gmail.com>2025-03-05 14:02:13 +0700
commit006c1171970a3ade5033d8bb112b7f6094b35d11 (patch)
treeff11743c553ebb6682b0640171318d9b322d427c
parent660913a45a1efe08f308d405e1011efc9744c553 (diff)
parent92b6da28414fed56732f86e1f04ea2fac3464d7d (diff)
Merge branch 'odoo-production' into dev/wms
# Conflicts: # indoteknik_custom/models/__init__.py # indoteknik_custom/models/stock_immediate_transfer.py # indoteknik_custom/models/stock_picking.py
-rw-r--r--indoteknik_api/controllers/api_v1/sale_order.py7
-rw-r--r--indoteknik_api/controllers/api_v1/stock_picking.py2
-rw-r--r--indoteknik_api/controllers/api_v1/user.py20
-rw-r--r--indoteknik_api/controllers/api_v1/voucher.py22
-rwxr-xr-xindoteknik_custom/__manifest__.py3
-rwxr-xr-xindoteknik_custom/models/__init__.py5
-rw-r--r--indoteknik_custom/models/account_move.py17
-rw-r--r--indoteknik_custom/models/account_move_due_extension.py1
-rw-r--r--indoteknik_custom/models/account_move_line.py9
-rw-r--r--indoteknik_custom/models/account_payment_register.py48
-rw-r--r--indoteknik_custom/models/automatic_purchase.py141
-rw-r--r--indoteknik_custom/models/barcoding_product.py8
-rw-r--r--indoteknik_custom/models/commision.py18
-rw-r--r--indoteknik_custom/models/coretax_fatur.py3
-rw-r--r--indoteknik_custom/models/invoice_reklas.py4
-rw-r--r--indoteknik_custom/models/invoice_reklas_penjualan.py2
-rw-r--r--indoteknik_custom/models/ir_actions_report.py51
-rwxr-xr-xindoteknik_custom/models/product_template.py38
-rwxr-xr-xindoteknik_custom/models/purchase_order.py31
-rwxr-xr-xindoteknik_custom/models/purchase_order_line.py60
-rw-r--r--indoteknik_custom/models/purchase_order_multi_ask_approval.py22
-rw-r--r--indoteknik_custom/models/purchase_order_multi_uangmuka.py2
-rw-r--r--indoteknik_custom/models/purchase_order_sales_match.py12
-rw-r--r--indoteknik_custom/models/purchasing_job.py1
-rw-r--r--indoteknik_custom/models/report_logbook_sj.py2
-rw-r--r--indoteknik_custom/models/report_stock_forecasted.py49
-rw-r--r--indoteknik_custom/models/requisition.py42
-rw-r--r--indoteknik_custom/models/res_partner.py14
-rwxr-xr-xindoteknik_custom/models/res_users.py4
-rwxr-xr-xindoteknik_custom/models/sale_order.py161
-rw-r--r--indoteknik_custom/models/sale_order_line.py6
-rw-r--r--indoteknik_custom/models/sale_order_multi_uangmuka_penjualan.py2
-rw-r--r--indoteknik_custom/models/solr/product_template.py7
-rw-r--r--indoteknik_custom/models/stock_immediate_transfer.py1
-rw-r--r--indoteknik_custom/models/stock_inventory.py59
-rw-r--r--indoteknik_custom/models/stock_picking.py45
-rw-r--r--indoteknik_custom/models/uangmuka_pembelian.py2
-rw-r--r--indoteknik_custom/models/uangmuka_penjualan.py2
-rw-r--r--indoteknik_custom/models/user_company_request.py6
-rw-r--r--indoteknik_custom/models/user_pengajuan_tempo_request.py75
-rw-r--r--indoteknik_custom/models/voucher.py6
-rw-r--r--indoteknik_custom/models/website_telegram.py193
-rwxr-xr-xindoteknik_custom/security/ir.model.access.csv7
-rw-r--r--indoteknik_custom/views/account_move.xml4
-rw-r--r--indoteknik_custom/views/barcoding_product.xml7
-rw-r--r--indoteknik_custom/views/customer_commision.xml9
-rwxr-xr-xindoteknik_custom/views/purchase_order.xml23
-rw-r--r--indoteknik_custom/views/purchase_order_multi_ask_approval.xml31
-rw-r--r--indoteknik_custom/views/report_logbook_sj.xml10
-rw-r--r--indoteknik_custom/views/res_partner.xml1
-rw-r--r--indoteknik_custom/views/res_users.xml2
-rwxr-xr-xindoteknik_custom/views/sale_order.xml28
-rw-r--r--indoteknik_custom/views/stock_inventory.xml28
-rw-r--r--indoteknik_custom/views/stock_picking.xml4
-rw-r--r--indoteknik_custom/views/user_pengajuan_tempo.xml2
-rw-r--r--indoteknik_custom/views/user_pengajuan_tempo_request.xml18
-rwxr-xr-xindoteknik_custom/views/voucher.xml1
-rw-r--r--indoteknik_custom/views/website_telegram.xml59
58 files changed, 1220 insertions, 217 deletions
diff --git a/indoteknik_api/controllers/api_v1/sale_order.py b/indoteknik_api/controllers/api_v1/sale_order.py
index 8b95ade8..a7e027c8 100644
--- a/indoteknik_api/controllers/api_v1/sale_order.py
+++ b/indoteknik_api/controllers/api_v1/sale_order.py
@@ -394,7 +394,8 @@ class SaleOrder(controller.Controller):
# Fetch partner details
sales_partner = request.env['res.partner'].browse(params['value']['partner_id'])
-
+ partner_invoice = request.env['res.partner'].browse(params['value']['partner_invoice_id'])
+ main_partner = partner_invoice.get_main_parent()
parameters = {
'warehouse_id': 8,
'carrier_id': 1,
@@ -410,7 +411,7 @@ class SaleOrder(controller.Controller):
'partner_id': params['value']['partner_id'],
'partner_shipping_id': params['value']['partner_shipping_id'],
'real_shipping_id': params['value']['partner_shipping_id'],
- 'partner_invoice_id': params['value']['partner_invoice_id'],
+ 'partner_invoice_id': main_partner.id,
'real_invoice_id': params['value']['partner_invoice_id'],
'partner_purchase_order_name': params['value']['po_number'],
'partner_purchase_order_file': params['value']['po_file'],
@@ -426,7 +427,7 @@ class SaleOrder(controller.Controller):
'npwp': sales_partner.npwp or '0', # Get NPWP from partner
'sppkp': sales_partner.sppkp, # Get SPPKP from partner
'email': sales_partner.email, # Get Email from partner
- 'user_id': 3222 # User ID: Nadia Rauhadatul Firdaus
+ 'user_id': 11314 # User ID: Boy Revandi
}
sales_partner = request.env['res.partner'].browse(parameters['partner_id'])
diff --git a/indoteknik_api/controllers/api_v1/stock_picking.py b/indoteknik_api/controllers/api_v1/stock_picking.py
index 110cde8a..2e0c4ad0 100644
--- a/indoteknik_api/controllers/api_v1/stock_picking.py
+++ b/indoteknik_api/controllers/api_v1/stock_picking.py
@@ -57,7 +57,7 @@ class StockPicking(controller.Controller):
if params['status'] == 'pending':
domain += pending_domain
elif params['status'] == 'shipment':
- domain += shipment_domain
+ domain += shipment_domain + shipment_domain2
elif params['status'] == 'completed':
domain += completed_domain
diff --git a/indoteknik_api/controllers/api_v1/user.py b/indoteknik_api/controllers/api_v1/user.py
index f651d9fa..c0974367 100644
--- a/indoteknik_api/controllers/api_v1/user.py
+++ b/indoteknik_api/controllers/api_v1/user.py
@@ -98,7 +98,7 @@ class User(controller.Controller):
user.partner_id.npwp = '00.000.000.0-000.000'
user.partner_id.sppkp = '-'
user.partner_id.nama_wajib_pajak = user.name
- user.partner_id.user_id = 3222
+ user.partner_id.user_id = 11314
user.partner_id.property_account_receivable_id = 395
user.partner_id.property_account_payable_id = 438
data = {
@@ -130,6 +130,7 @@ class User(controller.Controller):
alamat_bisnis = kw.get('alamat_bisnis', False)
nama_wajib_pajak = kw.get('nama_wajib_pajak', False)
is_pkp = kw.get('is_pkp')
+ is_terdaftar = kw.get('is_terdaftar', False)
type_acc = kw.get('type_acc', 'individu') or 'individu'
if not name or not email or not password:
@@ -168,18 +169,19 @@ class User(controller.Controller):
if type_acc == 'business' and business_name:
# Eksekusi query SQL menggunakan Levenshtein distance
query = """
- SELECT name, levenshtein(name::text, %s) AS distance
+ SELECT id, name, levenshtein(name::text, %s) AS distance
FROM res_partner
- WHERE levenshtein(name::text, %s) < 3
+ WHERE is_company = true AND active = true
+ AND levenshtein(name::text, %s) < 3
ORDER BY distance ASC
"""
params = (business_name, business_name)
request.env.cr.execute(query, params)
result = request.env.cr.fetchone()
- if result:
- match_company_name = result[0]
- match_company_id = result[2]
+ if result and is_terdaftar:
+ match_company_name = result[2]
+ match_company_id = result[0]
# Create a user company request
request.env['user.company.request'].create({
@@ -206,7 +208,7 @@ class User(controller.Controller):
'email': email_partner,
'street': alamat_bisnis,
'company_type': 'company',
- 'user_id': 3222,
+ 'user_id': 11314,
'property_account_receivable_id': 395,
'property_account_payable_id': 438,
'active': False,
@@ -251,7 +253,7 @@ class User(controller.Controller):
user.partner_id.npwp = '00.000.000.0-000.000'
user.partner_id.sppkp = '-'
user.partner_id.nama_wajib_pajak = name
- user.partner_id.user_id = 3222
+ user.partner_id.user_id = 11314
user.partner_id.property_account_receivable_id= 395
user.partner_id.property_account_payable_id = 438
@@ -603,7 +605,7 @@ class User(controller.Controller):
'email': email_partner,
'street': alamat_bisnis,
'company_type': 'company',
- 'user_id': 3222,
+ 'user_id': 11314,
'property_account_receivable_id': 395,
'property_account_payable_id': 438,
'active': False,
diff --git a/indoteknik_api/controllers/api_v1/voucher.py b/indoteknik_api/controllers/api_v1/voucher.py
index 910488d1..9ffeeace 100644
--- a/indoteknik_api/controllers/api_v1/voucher.py
+++ b/indoteknik_api/controllers/api_v1/voucher.py
@@ -22,9 +22,14 @@ class Voucher(controller.Controller):
code = kw.get('code')
type = kw.get('type')
user_id = int(kw.get('user_id', 0))
+ partner_id = int(kw.get('partner_id', 0))
source = kw.get('source')
visibility = ['public']
+ user = request.env['res.users'].search([('id', '=', user_id)], limit=1)
+ if not user:
+ return self.response([])
+
domain = []
if code:
visibility.append('private')
@@ -37,14 +42,19 @@ class Voucher(controller.Controller):
type = type.split(',')
domain += [('apply_type', 'in', type)]
+ if partner_id:
+ partner = request.env['res.partner'].search([('id', '=', partner_id)], limit=1)
+ main_parent = partner.get_main_parent()
+ if main_parent and main_parent.company_type:
+ domain += [('account_type', 'in', ['all',main_parent.company_type])]
+ # domain += [('account_type', 'in', main_parent.company_type)]
+
+
domain += [('visibility', 'in', visibility)]
vouchers = request.env['voucher'].get_active_voucher(domain)
checkout = cart.get_user_checkout(user_id, source=source)
products = checkout['products']
- user = request.env['res.users'].search([('id', '=', user_id)], limit=1)
- if not user:
- return self.response([])
order_line = []
for product in products:
@@ -89,3 +99,9 @@ class Voucher(controller.Controller):
sorted_results = sorted(results, key=lambda x: x['can_apply'], reverse=True)
return self.response(sorted_results)
+
+ def get_user_by_email(self, email):
+ return request.env['res.users'].search([
+ ('login', '=', email),
+ ('active', 'in', [True, False])
+ ]) \ No newline at end of file
diff --git a/indoteknik_custom/__manifest__.py b/indoteknik_custom/__manifest__.py
index 67a41a08..f66314fa 100755
--- a/indoteknik_custom/__manifest__.py
+++ b/indoteknik_custom/__manifest__.py
@@ -60,6 +60,7 @@
'views/website_brand_homepage.xml',
'views/website_categories_homepage.xml',
'views/website_categories_management.xml',
+ 'views/website_telegram.xml',
'views/website_categories_lob.xml',
'views/sales_target.xml',
'views/purchase_outstanding.xml',
@@ -117,6 +118,7 @@
'views/sale_monitoring_detail_v2.xml',
'views/purchase_order_multi_update.xml',
'views/purchase_order_multi_confirm.xml',
+ 'views/purchase_order_multi_ask_approval.xml',
'views/invoice_reklas_penjualan.xml',
'views/po_multi_cancel.xml',
'views/logbook_sj.xml',
@@ -160,6 +162,7 @@
'report/report_picking.xml',
'report/report_sale_order.xml',
'views/coretax_faktur.xml',
+ 'views/stock_inventory.xml',
],
'demo': [],
'css': [],
diff --git a/indoteknik_custom/models/__init__.py b/indoteknik_custom/models/__init__.py
index a5297806..531767fe 100755
--- a/indoteknik_custom/models/__init__.py
+++ b/indoteknik_custom/models/__init__.py
@@ -106,6 +106,7 @@ from . import sale_monitoring_detail_v2
from . import purchase_order_multi_update
from . import invoice_reklas_penjualan
from . import purchase_order_multi_confirm
+from . import purchase_order_multi_ask_approval
from . import po_multi_cancel
from . import logbook_sj
from . import report_logbook_sj
@@ -131,6 +132,7 @@ 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
@@ -139,6 +141,9 @@ 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 barcoding_product
from . import sales_order_koli
from . import stock_backorder_confirmation
+from . import account_payment_register
+from . import stock_inventory
diff --git a/indoteknik_custom/models/account_move.py b/indoteknik_custom/models/account_move.py
index 4553e446..9aa0743b 100644
--- a/indoteknik_custom/models/account_move.py
+++ b/indoteknik_custom/models/account_move.py
@@ -63,6 +63,20 @@ class AccountMove(models.Model):
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')
+ is_hr = fields.Boolean(string="Is HR?", default=False)
+ purchase_order_id = fields.Many2one('purchase.order', string='Purchase Order')
+
+ def _update_line_name_from_ref(self):
+ """Update all account.move.line name fields with ref from account.move"""
+ for move in self:
+ if move.move_type == 'entry' and move.ref and move.line_ids:
+ for line in move.line_ids:
+ line.name = move.ref
+
+ 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:
@@ -102,6 +116,7 @@ class AccountMove(models.Model):
def create(self, vals):
vals['nomor_kwitansi'] = self.env['ir.sequence'].next_by_code('nomor.kwitansi') or '0'
result = super(AccountMove, self).create(vals)
+ # result._update_line_name_from_ref()
return result
def compute_so_shipping_paid_by(self):
@@ -353,7 +368,7 @@ class AccountMove(models.Model):
def export_faktur_to_xml(self):
- valid_invoices = self.validate_faktur_for_export()
+ valid_invoices = self
# Panggil model coretax.faktur untuk menghasilkan XML
coretax_faktur = self.env['coretax.faktur'].create({})
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/account_move_line.py b/indoteknik_custom/models/account_move_line.py
index a4b25109..7c95d4ef 100644
--- a/indoteknik_custom/models/account_move_line.py
+++ b/indoteknik_custom/models/account_move_line.py
@@ -7,6 +7,7 @@ class AccountMoveLine(models.Model):
cost_centre_id = fields.Many2one('cost.centre', string='Cost Centre')
is_required = fields.Boolean(string='Is Required', compute='_compute_is_required')
analytic_account_ids = fields.Many2many('account.analytic.account', string='Analytic Account')
+ line_no = fields.Integer('No', default=0)
@api.onchange('account_id')
def _onchange_account_id(self):
@@ -22,3 +23,11 @@ class AccountMoveLine(models.Model):
else:
account.is_required = False
+ @api.model_create_multi
+ def create(self, vals_list):
+ for vals in vals_list:
+ if 'move_id' in vals:
+ move = self.env['account.move'].browse(vals['move_id'])
+ if move.move_type == 'entry' and move.is_hr == True:
+ vals['name'] = move.ref
+ return super().create(vals_list) \ No newline at end of file
diff --git a/indoteknik_custom/models/account_payment_register.py b/indoteknik_custom/models/account_payment_register.py
new file mode 100644
index 00000000..4ebb7e4e
--- /dev/null
+++ b/indoteknik_custom/models/account_payment_register.py
@@ -0,0 +1,48 @@
+# -*- coding: utf-8 -*-
+
+from odoo import models, fields, api, _
+from odoo.exceptions import UserError
+
+
+class AccountPaymentRegister(models.TransientModel):
+ _inherit = 'account.payment.register'
+ def _create_payment_vals_from_wizard(self):
+ payment_vals = {
+ 'date': self.payment_date,
+ 'amount': self.amount,
+ 'payment_type': self.payment_type,
+ 'partner_type': self.partner_type,
+ 'ref': self.communication,
+ 'journal_id': self.journal_id.id,
+ 'is_hr': True,
+ 'currency_id': self.currency_id.id,
+ 'partner_id': self.partner_id.id,
+ 'partner_bank_id': self.partner_bank_id.id,
+ 'payment_method_id': self.payment_method_id.id,
+ 'destination_account_id': self.line_ids[0].account_id.id
+ }
+
+ if not self.currency_id.is_zero(self.payment_difference) and self.payment_difference_handling == 'reconcile':
+ payment_vals['write_off_line_vals'] = {
+ 'name': self.writeoff_label,
+ 'amount': self.payment_difference,
+ 'account_id': self.writeoff_account_id.id,
+ }
+ return payment_vals
+
+ def _create_payment_vals_from_batch(self, batch_result):
+ batch_values = self._get_wizard_values_from_batch(batch_result)
+ return {
+ 'date': self.payment_date,
+ 'amount': batch_values['source_amount_currency'],
+ 'payment_type': batch_values['payment_type'],
+ 'partner_type': batch_values['partner_type'],
+ 'ref': self._get_batch_communication(batch_result),
+ 'journal_id': self.journal_id.id,
+ 'is_hr': True,
+ 'currency_id': batch_values['source_currency_id'],
+ 'partner_id': batch_values['partner_id'],
+ 'partner_bank_id': batch_result['key_values']['partner_bank_id'],
+ 'payment_method_id': self.payment_method_id.id,
+ 'destination_account_id': batch_result['lines'][0].account_id.id
+ }
diff --git a/indoteknik_custom/models/automatic_purchase.py b/indoteknik_custom/models/automatic_purchase.py
index 09d283eb..fbdf8dae 100644
--- a/indoteknik_custom/models/automatic_purchase.py
+++ b/indoteknik_custom/models/automatic_purchase.py
@@ -183,89 +183,94 @@ class AutomaticPurchase(models.Model):
def create_po_by_vendor(self, vendor_id):
current_time = datetime.now()
- if not self.apo_type =='reordering':
- name = "/PJ/"
- else:
- name = "/A/"
+ name = "/PJ/" if not self.apo_type == 'reordering' else "/A/"
PRODUCT_PER_PO = 20
-
auto_purchase_line = self.env['automatic.purchase.line']
- last_po = self.env['purchase.order'].search([
- ('partner_id', '=', vendor_id),
- ('state', '=', 'done'),
- ], order='id desc', limit=1)
-
- param_header = {
- 'partner_id': vendor_id,
- 'currency_id': 12,
- 'user_id': self.env.user.id,
- 'company_id': 1, # indoteknik dotcom gemilang
- 'picking_type_id': 28, # indoteknik bandengan receipts
- 'date_order': current_time,
- 'from_apo': True,
- 'note_description': 'Automatic PO'
- }
-
+ # Domain untuk semua baris dengan vendor_id tertentu
domain = [
('automatic_purchase_id', '=', self.id),
('partner_id', '=', vendor_id),
('qty_purchase', '>', 0)
]
- products_len = auto_purchase_line.search_count(domain)
- page = math.ceil(products_len / PRODUCT_PER_PO)
-
- # i start from zero (0)
- for i in range(page):
- new_po = self.env['purchase.order'].create([param_header])
- new_po.payment_term_id = new_po.partner_id.property_supplier_payment_term_id
- new_po.name = new_po.name + name + str(i + 1)
+ # Tambahkan domain khusus untuk brand_id 22 dan 564
+ special_brand_domain = domain + [('brand_id', 'in', [22, 564])]
+ regular_domain = domain + [('brand_id', 'not in', [22, 564])]
+
+ # Fungsi untuk membuat PO berdasarkan domain tertentu
+ def create_po_for_domain(domain, special_payment_term=False):
+ products_len = auto_purchase_line.search_count(domain)
+ page = math.ceil(products_len / PRODUCT_PER_PO)
+
+ for i in range(page):
+ # Buat PO baru
+ param_header = {
+ 'partner_id': vendor_id,
+ 'currency_id': 12,
+ 'user_id': self.env.user.id,
+ 'company_id': 1, # indoteknik dotcom gemilang
+ 'picking_type_id': 28, # indoteknik bandengan receipts
+ 'date_order': current_time,
+ 'from_apo': True,
+ 'note_description': 'Automatic PO'
+ }
- self.env['automatic.purchase.match'].create([{
- 'automatic_purchase_id': self.id,
- 'order_id': new_po.id
- }])
+ new_po = self.env['purchase.order'].create([param_header])
- lines = auto_purchase_line.search(
- domain,
- offset=i * PRODUCT_PER_PO,
- limit=PRODUCT_PER_PO
- )
+ # Set payment_term_id khusus jika diperlukan
+ if special_payment_term:
+ new_po.payment_term_id = 29
+ else:
+ new_po.payment_term_id = new_po.partner_id.property_supplier_payment_term_id
- lines = auto_purchase_line.search(
- domain,
- offset=i * PRODUCT_PER_PO,
- limit=PRODUCT_PER_PO
- )
+ new_po.name = new_po.name + name + str(i + 1)
+ self.env['automatic.purchase.match'].create([{
+ 'automatic_purchase_id': self.id,
+ 'order_id': new_po.id
+ }])
+
+ # Ambil baris sesuai halaman
+ lines = auto_purchase_line.search(
+ domain,
+ offset=i * PRODUCT_PER_PO,
+ limit=PRODUCT_PER_PO
+ )
+
+ for line in lines:
+ product = line.product_id
+ sales_match = self.env['automatic.purchase.sales.match'].search([
+ ('automatic_purchase_id', '=', self.id),
+ ('product_id', '=', product.id),
+ ])
+ param_line = {
+ 'order_id': new_po.id,
+ 'product_id': product.id,
+ 'product_qty': line.qty_purchase,
+ 'qty_available_store': product.qty_available_bandengan,
+ '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
+ }
+ new_po_line = self.env['purchase.order.line'].create([param_line])
+ line.current_po_id = new_po.id
+ line.current_po_line_id = new_po_line.id
+
+ self.create_purchase_order_sales_match(new_po)
+
+ # Buat PO untuk special brand
+ if vendor_id == 23:
+ create_po_for_domain(special_brand_domain, special_payment_term=True)
+
+ # Buat PO untuk regular domain
+ create_po_for_domain(regular_domain, "")
- for line in lines:
- product = line.product_id
- sales_match = self.env['automatic.purchase.sales.match'].search([
- ('automatic_purchase_id', '=', self.id),
- ('product_id', '=', product.id),
- ])
- param_line = {
- 'order_id': new_po.id,
- 'product_id': product.id,
- 'product_qty': line.qty_purchase,
- 'qty_available_store': product.qty_available_bandengan,
- '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
- }
- new_po_line = self.env['purchase.order.line'].create([param_line])
- line.current_po_id = new_po.id
- line.current_po_line_id = new_po_line.id
- # self.update_purchase_price_so_line(line)
-
- self.create_purchase_order_sales_match(new_po)
def update_purchase_price_so_line(self, apo):
sales_match = self.env['automatic.purchase.sales.match'].search([
diff --git a/indoteknik_custom/models/barcoding_product.py b/indoteknik_custom/models/barcoding_product.py
index 6bbf9fde..e1b8f41f 100644
--- a/indoteknik_custom/models/barcoding_product.py
+++ b/indoteknik_custom/models/barcoding_product.py
@@ -12,6 +12,14 @@ class BarcodingProduct(models.Model):
barcoding_product_line = fields.One2many('barcoding.product.line', 'barcoding_product_id', string='Barcoding Product Lines', auto_join=True)
product_id = fields.Many2one('product.product', string="Product", tracking=3)
quantity = fields.Float(string="Quantity", tracking=3)
+ type = fields.Selection([('print', 'Print Barcode'), ('barcoding', 'Add Barcode To Product')], string='Type', default='print')
+ barcode = fields.Char(string="Barcode")
+
+ @api.constrains('barcode')
+ def _send_barcode_to_product(self):
+ for record in self:
+ if record.barcode and not record.product_id.barcode:
+ record.product_id.barcode = record.barcode
@api.onchange('product_id', 'quantity')
def _onchange_product_or_quantity(self):
diff --git a/indoteknik_custom/models/commision.py b/indoteknik_custom/models/commision.py
index 48f1c7f6..6920154a 100644
--- a/indoteknik_custom/models/commision.py
+++ b/indoteknik_custom/models/commision.py
@@ -153,6 +153,10 @@ class CustomerCommision(models.Model):
bank_account = fields.Char(string='Account No', tracking=3)
note_transfer = fields.Char(string='Keterangan')
brand_ids = fields.Many2many('x_manufactures', string='Brands')
+ payment_status = fields.Selection([
+ ('pending', 'Pending'),
+ ('payment', 'Payment'),
+ ], string='Payment Status', copy=False, readonly=True, tracking=3, default='pending')
# add status for type of commision, fee, rebate / cashback
# include child or not?
@@ -228,6 +232,20 @@ class CustomerCommision(models.Model):
raise UserError('Harus di approved oleh yang bersangkutan')
return
+ def action_confirm_customer_payment(self):
+ if self.status != 'approved':
+ raise UserError('Commision harus di approve terlebih dahulu sebelum di konfirmasi pembayarannya')
+
+ if self.payment_status == 'payment':
+ raise UserError('Customer Commision sudah berstatus Payment')
+ group_id = self.env.ref('indoteknik_custom.group_role_fat').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('Hanya bisa dikonfirmasi oleh FAT')
+ else:
+ self.payment_status = 'payment'
+ return
+
def generate_customer_commision(self):
if self.commision_lines:
raise UserError('Line sudah ada, tidak bisa di generate ulang')
diff --git a/indoteknik_custom/models/coretax_fatur.py b/indoteknik_custom/models/coretax_fatur.py
index ae6dd2ae..b4bffbd2 100644
--- a/indoteknik_custom/models/coretax_fatur.py
+++ b/indoteknik_custom/models/coretax_fatur.py
@@ -59,6 +59,7 @@ class CoretaxFaktur(models.Model):
ET.SubElement(tax_invoice, 'TrxCode').text = '04'
ET.SubElement(tax_invoice, 'AddInfo')
ET.SubElement(tax_invoice, 'CustomDoc')
+ ET.SubElement(tax_invoice, 'CustomDocMonthYear')
ET.SubElement(tax_invoice, 'RefDesc').text = invoice.name
ET.SubElement(tax_invoice, 'FacilityStamp')
ET.SubElement(tax_invoice, 'SellerIDTKU').text = '0742260227086000000000'
@@ -77,7 +78,7 @@ class CoretaxFaktur(models.Model):
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, 'Code').text = '000000'
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'
diff --git a/indoteknik_custom/models/invoice_reklas.py b/indoteknik_custom/models/invoice_reklas.py
index 30da02d1..f5bb5a25 100644
--- a/indoteknik_custom/models/invoice_reklas.py
+++ b/indoteknik_custom/models/invoice_reklas.py
@@ -49,7 +49,7 @@ class InvoiceReklas(models.TransientModel):
if self.reklas_type == 'penjualan':
parameter_debit = {
'move_id': account_move.id,
- 'account_id': 449, # uang muka penjualan
+ 'account_id': 668, # penerimaan belum alokasi
'partner_id': invoice.partner_id.id,
'currency_id': 12,
'debit': self.pay_amt,
@@ -77,7 +77,7 @@ class InvoiceReklas(models.TransientModel):
}
parameter_credit = {
'move_id': account_move.id,
- 'account_id': 401,
+ 'account_id': 669,
'partner_id': invoice.partner_id.id,
'currency_id': 12,
'debit': 0,
diff --git a/indoteknik_custom/models/invoice_reklas_penjualan.py b/indoteknik_custom/models/invoice_reklas_penjualan.py
index 5027c8af..80c3ed43 100644
--- a/indoteknik_custom/models/invoice_reklas_penjualan.py
+++ b/indoteknik_custom/models/invoice_reklas_penjualan.py
@@ -33,7 +33,7 @@ class InvoiceReklasPenjualan(models.TransientModel):
parameter_debit = {
'move_id': account_move.id,
- 'account_id': 449, # uang muka penjualan
+ 'account_id': 668, # uang muka penjualan
'partner_id': invoice.partner_id.id,
'currency_id': 12,
'debit': invoice.pay_amt,
diff --git a/indoteknik_custom/models/ir_actions_report.py b/indoteknik_custom/models/ir_actions_report.py
new file mode 100644
index 00000000..83636945
--- /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 = '-1002493002821'
+ bot_name_vita = '7751529082:AAE9XsZa_Pj2Pi2IN1grX98WkwTaIt32pbI'
+ chat_id_vita = '5081411103'
+ apiURL = f'https://api.telegram.org/bot{bot_name_iman}/sendMessage'
+ try:
+ requests.post(apiURL, json={'chat_id': chat_id_iman, '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/product_template.py b/indoteknik_custom/models/product_template.py
index 29608297..efacb95f 100755
--- a/indoteknik_custom/models/product_template.py
+++ b/indoteknik_custom/models/product_template.py
@@ -67,6 +67,25 @@ class ProductTemplate(models.Model):
print_barcode = fields.Boolean(string='Print Barcode', default=True)
# qr_code = fields.Binary("QR Code", compute='_compute_qr_code')
+ @api.model
+ def create(self, vals):
+ group_id = self.env.ref('indoteknik_custom.group_role_merchandiser').id
+ users_in_group = self.env['res.users'].search([('groups_id', 'in', [group_id])])
+ active_model = self.env.context.get('active_model')
+ if self.env.user.id not in users_in_group.mapped('id') and active_model == None:
+ raise UserError('Hanya MD yang bisa membuat Product')
+ result = super(ProductTemplate, self).create(vals)
+ return result
+
+ # def write(self, values):
+ # group_id = self.env.ref('indoteknik_custom.group_role_merchandiser').id
+ # users_in_group = self.env['res.users'].search([('groups_id', 'in', [group_id])])
+ # active_model = self.env.context.get('active_model')
+ # if self.env.user.id not in users_in_group.mapped('id') and active_model == None:
+ # raise UserError('Hanya MD yang bisa mengedit Product')
+ # result = super(ProductTemplate, self).write(values)
+ # return result
+
# def _compute_qr_code(self):
# for rec in self.product_variant_ids:
# qr = qrcode.QRCode(
@@ -403,6 +422,25 @@ class ProductProduct(models.Model):
merchandise_ok = fields.Boolean(string='Product Promotion')
qr_code_variant = fields.Binary("QR Code Variant", compute='_compute_qr_code_variant')
+ @api.model
+ def create(self, vals):
+ group_id = self.env.ref('indoteknik_custom.group_role_merchandiser').id
+ active_model = self.env.context.get('active_model')
+ 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') and active_model == None:
+ raise UserError('Hanya MD yang bisa membuat Product')
+ result = super(ProductProduct, self).create(vals)
+ return result
+
+ # def write(self, values):
+ # group_id = self.env.ref('indoteknik_custom.group_role_merchandiser').id
+ # active_model = self.env.context.get('active_model')
+ # 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') and active_model == None:
+ # raise UserError('Hanya MD yang bisa mengedit Product')
+ # result = super(ProductProduct, self).write(values)
+ # return result
+
def _compute_qr_code_variant(self):
for rec in self:
# Skip inactive variants
diff --git a/indoteknik_custom/models/purchase_order.py b/indoteknik_custom/models/purchase_order.py
index 777e8ed2..d90c4a8a 100755
--- a/indoteknik_custom/models/purchase_order.py
+++ b/indoteknik_custom/models/purchase_order.py
@@ -86,6 +86,7 @@ class PurchaseOrder(models.Model):
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')
+ purchase_order_count = fields.Integer('Purchase Order Count', related='partner_id.purchase_order_count')
@api.onchange('total_cost_service')
def _onchange_total_cost_service(self):
@@ -154,6 +155,7 @@ class PurchaseOrder(models.Model):
'invoice_date': current_date,
'date': current_date,
'invoice_origin': self.name,
+ 'purchase_order_id': self.id,
'move_type': 'in_invoice'
}
@@ -178,7 +180,7 @@ class PurchaseOrder(models.Model):
'move_id': bills.id,
'product_id': product_dp.id, # product down payment
'name': '[IT.121456] Down Payment', # product down payment
- 'account_id': 401, # Uang Muka persediaan barang dagang
+ 'account_id': 669, # Uang Muka persediaan barang dagang
# 'price_unit': move_line.price_unit,
'quantity': -1,
'product_uom_id': 1,
@@ -230,6 +232,7 @@ class PurchaseOrder(models.Model):
'invoice_date': current_date,
'date': current_date,
'invoice_origin': self.name,
+ 'purchase_order_id': self.id,
'move_type': 'in_invoice'
}
@@ -240,7 +243,7 @@ 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
+ 'account_id': 669, # Uang Muka persediaan barang dagang
'quantity': 1,
'product_uom_id': 1,
'tax_ids': [line[0].taxes_id.id for line in self.order_line],
@@ -306,6 +309,7 @@ class PurchaseOrder(models.Model):
invoice_vals = {
'ref': self.partner_ref or '',
'move_type': move_type,
+ 'purchase_order_id': self.id,
'narration': self.notes,
'currency_id': self.currency_id.id,
'invoice_user_id': self.user_id and self.user_id.id or self.env.user.id,
@@ -387,6 +391,13 @@ class PurchaseOrder(models.Model):
}
return action
+ def open_form_multi_ask_approval_po(self):
+ action = self.env['ir.actions.act_window']._for_xml_id('indoteknik_custom.action_purchase_order_multi_ask_approval')
+ action['context'] = {
+ 'po_ids': [x.id for x in self]
+ }
+ return action
+
def open_form_multi_create_uang_muka(self):
action = self.env['ir.actions.act_window']._for_xml_id('indoteknik_custom.action_purchase_order_multi_uangmuka')
action['context'] = {
@@ -414,6 +425,13 @@ class PurchaseOrder(models.Model):
purchase.button_confirm()
+ def action_multi_ask_approval_po(self):
+ for purchase in self:
+ if purchase.state != 'draft':
+ continue
+
+ purchase.po_approve()
+
def open_form_multi_update_paid_status(self):
action = self.env['ir.actions.act_window']._for_xml_id('indoteknik_custom.action_purchase_order_multi_update')
action['context'] = {
@@ -965,7 +983,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:
diff --git a/indoteknik_custom/models/purchase_order_line.py b/indoteknik_custom/models/purchase_order_line.py
index 587a09a1..033469b8 100755
--- a/indoteknik_custom/models/purchase_order_line.py
+++ b/indoteknik_custom/models/purchase_order_line.py
@@ -321,32 +321,60 @@ class PurchaseOrderLine(models.Model):
def compute_item_margin(self):
sum_so_margin = sum_sales_price = sum_margin = 0
+
for line in self:
- if not line.product_id or line.product_id.type == 'service' or not self.order_id.sale_order_id:
+ product = line.product_id
+ order = line.order_id
+
+ # Skip jika tidak ada product_id, produk adalah service, atau tidak ada purchase order terkait
+ if not product or product.type == 'service' or not order:
line.so_item_margin = 0
line.so_item_percent_margin = 0
line.item_margin = 0
line.item_percent_margin = 0
continue
- sale_order_line = self.env['sale.order.line'].search(
- [('product_id', '=', line.product_id.id),
- ('order_id', '=', line.order_id.sale_order_id.id)], limit=1, order='price_reduce_taxexcl')
- line.so_item_margin = sale_order_line.item_margin
- line.so_item_percent_margin = sale_order_line.item_percent_margin
- sum_so_margin += sale_order_line.item_margin
- sales_price = sale_order_line.price_reduce_taxexcl * sale_order_line.product_uom_qty
- if sale_order_line.order_id.shipping_cost_covered == 'indoteknik':
- sales_price -= sale_order_line.delivery_amt_line
- if sale_order_line.order_id.fee_third_party > 0:
- sales_price -= sale_order_line.fee_third_party_line
- sum_sales_price += sales_price
+
+ # Cari semua sale.order.line terkait dengan purchase.order melalui tabel purchase.order.sales.match
+ sales_matches = self.env['purchase.order.sales.match'].search([
+ ('purchase_order_id', '=', order.id),
+ ('product_id', '=', product.id)
+ ])
+
+ total_sales_price = total_margin = total_qty_so = 0
+ for match in sales_matches:
+ sale_order_line = match.sale_line_id
+
+ # Hitung harga jual setelah mempertimbangkan biaya tambahan
+ sales_price = sale_order_line.price_reduce_taxexcl * match.qty_so
+ if sale_order_line.order_id.shipping_cost_covered == 'indoteknik':
+ sales_price -= sale_order_line.delivery_amt_line
+ if sale_order_line.order_id.fee_third_party > 0:
+ sales_price -= sale_order_line.fee_third_party_line
+
+ total_sales_price += sales_price
+ total_margin += sale_order_line.item_margin
+ total_qty_so += match.qty_so
+
+ # Set margin berdasarkan total dari semua sales order yang terkait
+ line.so_item_margin = total_margin
+ line.so_item_percent_margin = (total_margin / total_sales_price) * 100 if total_sales_price else 0
+
+ sum_so_margin += total_margin
+ sum_sales_price += total_sales_price
+
+ # Hitung harga pembelian dengan mempertimbangkan biaya pengiriman
purchase_price = line.price_subtotal
- if line.order_id.delivery_amount > 0:
+ if order.delivery_amount > 0:
purchase_price += line.delivery_amt_line
- real_item_margin = sales_price - purchase_price
- real_item_percent_margin = round((real_item_margin/sales_price), 2) * 100
+
+ # Hitung margin dan persentase margin
+ real_item_margin = total_sales_price - purchase_price
+ real_item_percent_margin = (real_item_margin / total_sales_price) * 100 if total_sales_price else 0
+
+ # Set nilai margin ke dalam line
line.item_margin = real_item_margin
line.item_percent_margin = real_item_percent_margin
+
sum_margin += real_item_margin
def compute_delivery_amt_line(self):
diff --git a/indoteknik_custom/models/purchase_order_multi_ask_approval.py b/indoteknik_custom/models/purchase_order_multi_ask_approval.py
new file mode 100644
index 00000000..69f8e5a8
--- /dev/null
+++ b/indoteknik_custom/models/purchase_order_multi_ask_approval.py
@@ -0,0 +1,22 @@
+from odoo import models, fields
+import logging
+
+_logger = logging.getLogger(__name__)
+
+
+class PurchaseOrderMultiUpdate(models.TransientModel):
+ _name = 'purchase.order.multi_ask_approval'
+
+ def save_multi_ask_approval_po(self):
+ po_ids = self._context['po_ids']
+ purchase = self.env['purchase.order'].browse(po_ids)
+ purchase.action_multi_ask_approval_po()
+ return {
+ 'type': 'ir.actions.client',
+ 'tag': 'display_notification',
+ 'params': {
+ 'title': 'Notification',
+ 'message': 'PO berhasil di ask_approval',
+ 'next': {'type': 'ir.actions.act_window_close'},
+ }
+ } \ No newline at end of file
diff --git a/indoteknik_custom/models/purchase_order_multi_uangmuka.py b/indoteknik_custom/models/purchase_order_multi_uangmuka.py
index dd63e698..0570efd9 100644
--- a/indoteknik_custom/models/purchase_order_multi_uangmuka.py
+++ b/indoteknik_custom/models/purchase_order_multi_uangmuka.py
@@ -76,7 +76,7 @@ class PurchaseOrderMultiUangmuka(models.TransientModel):
param_debit = {
'move_id': account_move.id,
- 'account_id': 401, # uang muka persediaan barang dagang
+ 'account_id': 669, # uang muka persediaan barang dagang
'partner_id': partner_id,
'currency_id': 12,
'debit': order.amount_total,
diff --git a/indoteknik_custom/models/purchase_order_sales_match.py b/indoteknik_custom/models/purchase_order_sales_match.py
index d1d929d3..ed013dd5 100644
--- a/indoteknik_custom/models/purchase_order_sales_match.py
+++ b/indoteknik_custom/models/purchase_order_sales_match.py
@@ -24,6 +24,18 @@ class PurchaseOrderSalesMatch(models.Model):
margin_item = fields.Float(string='Margin')
delivery_amt = fields.Float(string='Delivery Amount', compute='_compute_delivery_amt')
margin_deduct = fields.Float(string='After Deduct', compute='_compute_delivery_amt')
+ purchase_price_so = fields.Float(string='Purchase Price Sale Order', related='sale_line_id.purchase_price')
+ purchase_price_po = fields.Float('Purchase Price PO', compute='_compute_purchase_price_po')
+ purchase_line_id = fields.Many2one('purchase.order.line', string='Purchase Line', compute='_compute_purchase_line_id')
+
+ def _compute_purchase_line_id(self):
+ for line in self:
+ line.purchase_line_id = self.env['purchase.order.line'].search([('order_id', '=', line.purchase_order_id.id), ('product_id', '=', line.product_id.id)])
+
+ def _compute_purchase_price_po(self):
+ for line in self:
+ purchase_price = self.env['purchase.order.line'].search([('order_id', '=', line.purchase_order_id.id), ('product_id', '=', line.product_id.id)])
+ line.purchase_price_po = purchase_price.price_unit
def _compute_delivery_amt(self):
for line in self:
diff --git a/indoteknik_custom/models/purchasing_job.py b/indoteknik_custom/models/purchasing_job.py
index 4efb0cd4..902bc34b 100644
--- a/indoteknik_custom/models/purchasing_job.py
+++ b/indoteknik_custom/models/purchasing_job.py
@@ -183,6 +183,7 @@ class OutstandingSales(models.Model):
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')
+ and sm.state in ('draft', 'waiting', 'confirmed', 'partially_available')
and sp.name like '%OUT%'
)
""")
diff --git a/indoteknik_custom/models/report_logbook_sj.py b/indoteknik_custom/models/report_logbook_sj.py
index a1b6299c..17119c12 100644
--- a/indoteknik_custom/models/report_logbook_sj.py
+++ b/indoteknik_custom/models/report_logbook_sj.py
@@ -29,6 +29,8 @@ class ReportLogbookSJ(models.Model):
string='Status',
tracking=True,
)
+
+ sj_number = fields.Char(string='Picking', related='report_logbook_sj_line.name')
count_line = fields.Char(string='Count Line', compute='_compute_count_line')
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/requisition.py b/indoteknik_custom/models/requisition.py
index c972b485..1d350929 100644
--- a/indoteknik_custom/models/requisition.py
+++ b/indoteknik_custom/models/requisition.py
@@ -276,10 +276,11 @@ class RequisitionLine(models.Model):
_name = 'requisition.line'
_description = 'Requisition Line'
_order = 'requisition_id, id'
+ _inherit = ['mail.thread']
requisition_id = fields.Many2one('requisition', string='Ref', required=True, ondelete='cascade', index=True, copy=False)
brand_id = fields.Many2one('x_manufactures', string='Brand')
- product_id = fields.Many2one('product.product', string='Product')
+ product_id = fields.Many2one('product.product', string='Product', tracking=3,)
partner_id = fields.Many2one('res.partner', string='Vendor')
qty_purchase = fields.Float(string='Qty Purchase')
price_unit = fields.Float(string='Price')
@@ -331,6 +332,45 @@ class RequisitionLine(models.Model):
line.taxes_id = taxes
line.partner_id = purchase_pricelist.vendor_id.id
+ @api.model
+ def create(self, vals):
+ record = super(RequisitionLine, self).create(vals)
+ record._track_changes('Tambah')
+ return record
+
+ def write(self, vals):
+ for record in self:
+ old_values = {field: record[field] for field in vals if field in record}
+
+ result = super(RequisitionLine, self).write(vals)
+
+ for record in self:
+ record._track_changes('Updated', old_values)
+
+ return result
+
+ def unlink(self):
+ for record in self:
+ record._track_changes('Hapus')
+ return super(RequisitionLine, self).unlink()
+
+ def _track_changes(self, action, old_values=None):
+ message = f"Produk telah di-{action} : <br/>"
+ if action == 'Tambah':
+ # message += f"<br/> Product: {self.product_id.name}"
+ message += f"Product: {self.product_id.name} <br/> Vendor: {self.partner_id.name} <br/> Qty: {self.qty_purchase} <br/> Price: {self.price_unit} <br/> Tax: {self.tax_id.name} <br/> Subtotal: {self.subtotal} <br/> Brand: {self.brand_id.x_name}"
+ elif action == 'Hapus':
+ # message += f"<br/> Deleted Product: {self.product_id.name}"
+ message += f"<br/> Deleted Product: {self.product_id.name} <br/> Vendor: {self.partner_id.name} Qty: {self.qty_purchase} <br/> Price: {self.price_unit} <br/> Tax: {self.tax_id.name} <br/> Subtotal: {self.subtotal} <br/> Brand: {self.brand_id.x_name}"
+ else: # Updated
+ for field, old_value in old_values.items():
+ new_value = self[field]
+ if old_value != new_value:
+ field_label = self._fields[field].string # Ambil nama label field
+ message += f"{field_label}: {old_value} -> {new_value}<br/>"
+
+ if self.requisition_id:
+ self.requisition_id.message_post(body=message)
class RequisitionPurchaseMatch(models.Model):
_name = 'requisition.purchase.match'
diff --git a/indoteknik_custom/models/res_partner.py b/indoteknik_custom/models/res_partner.py
index f081e274..7e574a72 100644
--- a/indoteknik_custom/models/res_partner.py
+++ b/indoteknik_custom/models/res_partner.py
@@ -147,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")
@api.model
def _default_payment_term(self):
@@ -182,6 +183,19 @@ class ResPartner(models.Model):
# # raise UserError('You name it')
#
return res
+
+ @api.constrains('name')
+ def _check_duplicate_name(self):
+ for record in self:
+ if record.name:
+ # Mencari partner lain yang memiliki nama sama (case-insensitive)
+ existing_partner = self.env['res.partner'].search([
+ ('id', '!=', record.id), # Hindari mencocokkan diri sendiri
+ ('name', '=', record.name) # Case-insensitive search
+ ], limit=1)
+
+ if existing_partner:
+ raise ValidationError(f"Nama '{record.name}' sudah digunakan oleh partner lain!")
def write(self, vals):
# Fungsi rekursif untuk meng-update semua child, termasuk child dari child
diff --git a/indoteknik_custom/models/res_users.py b/indoteknik_custom/models/res_users.py
index 31b84ae3..b0864f2c 100755
--- a/indoteknik_custom/models/res_users.py
+++ b/indoteknik_custom/models/res_users.py
@@ -70,6 +70,10 @@ class ResUsers(models.Model):
vouchers = self.env['voucher'].get_active_voucher([('show_on_email', '=', 'user_activation')])
if not vouchers: return None
return ', '.join(x.code for x in vouchers)
+ if type == 'switch_account':
+ vouchers = self.env['voucher'].get_active_voucher([('excl_pricelist_ids', 'not in', [1]), ('apply_type', 'in', ['all', 'brand']), ('account_type', 'in', ['all', 'company']), ('visibility', 'in', ['public'])])
+ if not vouchers: return None
+ return ', '.join(x.code for x in vouchers)
return None
def check_access(self, model, mode):
diff --git a/indoteknik_custom/models/sale_order.py b/indoteknik_custom/models/sale_order.py
index 88c32fb6..3534306c 100755
--- a/indoteknik_custom/models/sale_order.py
+++ b/indoteknik_custom/models/sale_order.py
@@ -7,6 +7,50 @@ from collections import defaultdict
_logger = logging.getLogger(__name__)
+class CancelReasonOrder(models.TransientModel):
+ _name = 'cancel.reason.order'
+ _description = 'Wizard for Cancel Reason order'
+
+ request_id = fields.Many2one('sale.order', string='Request')
+ reason_cancel = fields.Selection([
+ ('harga_terlalu_mahal', 'Harga barang terlalu mahal'),
+ ('harga_web_tidak_valid', 'Harga web tidak valid'),
+ ('stok_kosong', 'Stock kosong'),
+ ('tidak_mau_indent', 'Customer tidak mau indent'),
+ ('batal_rencana_pembelian', 'Customer membatalkan rencana pembelian'),
+ ('vendor_tidak_support_demo', 'Vendor tidak support demo/trial product'),
+ ('product_knowledge_kurang', 'Product knowledge kurang baik'),
+ ('barang_tidak_sesuai', 'Barang tidak sesuai/tepat'),
+ ('tidak_sepakat_pembayaran', 'Tidak menemukan kesepakatan untuk pembayaran'),
+ ('dokumen_tidak_support', 'Indoteknik tidak bisa support document yang dibutuhkan (Ex: TKDN, COO, SNI)'),
+ ('ganti_quotation', 'Ganti Quotation'),
+ ('testing_internal', 'Testing Internal'),
+ ('revisi_data', 'Revisi Data'),
+ ], string='Reason for Cancel', required=True, copy=False, index=True, tracking=3)
+ attachment_bukti = fields.Many2many(
+ 'ir.attachment',
+ string="Attachment Bukti", readonly=False,
+ tracking=3, required=True
+ )
+ nomor_so_pengganti = fields.Char(string='Nomor SO Pengganti', copy=False, tracking=3)
+
+ def confirm_reject(self):
+ order = self.request_id
+ if order:
+ order.write({'reason_cancel': self.reason_cancel})
+ if not self.attachment_bukti:
+ raise UserError('Attachment bukti wajib disertakan')
+ order.write({'attachment_bukti': self.attachment_bukti})
+ order.message_post(body='Attachment Bukti Cancel',
+ attachment_ids=[self.attachment_bukti.id])
+ if self.reason_cancel == 'ganti_quotation':
+ if self.nomor_so_pengganti:
+ order.write({'nomor_so_pengganti': self.nomor_so_pengganti})
+ else:
+ raise UserError('Nomor SO pengganti wajib disertakan')
+ order.confirm_cancel_order()
+
+ return {'type': 'ir.actions.act_window_close'}
class SaleOrder(models.Model):
_inherit = "sale.order"
@@ -29,11 +73,11 @@ class SaleOrder(models.Model):
shipping_cost_covered = fields.Selection([
('indoteknik', 'Indoteknik'),
('customer', 'Customer')
- ], string='Shipping Covered by', help='Siapa yang menanggung biaya ekspedisi?', copy=False)
+ ], string='Shipping Covered by', help='Siapa yang menanggung biaya ekspedisi?', copy=False, tracking=3)
shipping_paid_by = fields.Selection([
('indoteknik', 'Indoteknik'),
('customer', 'Customer')
- ], string='Shipping Paid by', help='Siapa yang talangin dulu Biaya ekspedisi-nya?', copy=False)
+ ], string='Shipping Paid by', help='Siapa yang talangin dulu Biaya ekspedisi-nya?', copy=False, tracking=3)
sales_tax_id = fields.Many2one('account.tax', string='Tax', domain=['|', ('active', '=', False), ('active', '=', True)])
have_outstanding_invoice = fields.Boolean('Have Outstanding Invoice', compute='_have_outstanding_invoice')
have_outstanding_picking = fields.Boolean('Have Outstanding Picking', compute='_have_outstanding_picking')
@@ -145,6 +189,34 @@ class SaleOrder(models.Model):
('PNR', 'Pareto Non Repeating'),
('NP', 'Non Pareto')
])
+ shipping_method_picking = fields.Char(string='Shipping Method Picking', compute='_compute_shipping_method_picking')
+ reason_cancel = fields.Selection([
+ ('harga_terlalu_mahal', 'Harga barang terlalu mahal'),
+ ('harga_web_tidak_valid', 'Harga web tidak valid'),
+ ('stok_kosong', 'Stock kosong'),
+ ('tidak_mau_indent', 'Customer tidak mau indent'),
+ ('batal_rencana_pembelian', 'Customer membatalkan rencana pembelian'),
+ ('vendor_tidak_support_demo', 'Vendor tidak support demo/trial product'),
+ ('product_knowledge_kurang', 'Product knowledge kurang baik'),
+ ('barang_tidak_sesuai', 'Barang tidak sesuai/tepat'),
+ ('tidak_sepakat_pembayaran', 'Tidak menemukan kesepakatan untuk pembayaran'),
+ ('dokumen_tidak_support', 'Indoteknik tidak bisa support document yang dibutuhkan (Ex: TKDN, COO, SNI)'),
+ ('ganti_quotation', 'Ganti Quotation'),
+ ('testing_internal', 'Testing Internal'),
+ ], string='Reason for Cancel', copy=False, index=True, tracking=3)
+ attachment_bukti = fields.Many2one(
+ 'ir.attachment',
+ string="Attachment Bukti Cancel", readonly=False,
+ )
+ nomor_so_pengganti = fields.Char(string='Nomor SO Pengganti', copy=False, tracking=3)
+
+ def _compute_shipping_method_picking(self):
+ for order in self:
+ if order.picking_ids:
+ carrier_names = order.picking_ids.mapped('carrier_id.name')
+ order.shipping_method_picking = ', '.join(filter(None, carrier_names))
+ else:
+ order.shipping_method_picking = False
@api.onchange('payment_status')
def _is_continue_transaction(self):
@@ -541,22 +613,22 @@ class SaleOrder(models.Model):
redirect_url = json.loads(lookup_json)['redirect_url']
self.payment_link_midtrans = str(redirect_url)
- # Generate QR code
- qr = qrcode.QRCode(
- version=1,
- error_correction=qrcode.constants.ERROR_CORRECT_L,
- box_size=10,
- border=4,
- )
- qr.add_data(redirect_url)
- qr.make(fit=True)
- img = qr.make_image(fill_color="black", back_color="white")
+ if 'redirect_url' in response:
+ qr = qrcode.QRCode(
+ version=1,
+ error_correction=qrcode.constants.ERROR_CORRECT_L,
+ box_size=10,
+ border=4,
+ )
+ qr.add_data(redirect_url)
+ qr.make(fit=True)
+ img = qr.make_image(fill_color="black", back_color="white")
- buffer = BytesIO()
- img.save(buffer, format="PNG")
- qr_code_img = base64.b64encode(buffer.getvalue()).decode()
+ buffer = BytesIO()
+ img.save(buffer, format="PNG")
+ qr_code_img = base64.b64encode(buffer.getvalue()).decode()
- self.payment_qr_code = qr_code_img
+ self.payment_qr_code = qr_code_img
@api.model
def _generate_so_access_token(self, limit=50):
@@ -760,6 +832,7 @@ class SaleOrder(models.Model):
def sale_order_approve(self):
self.check_credit_limit()
+ self.check_limit_so_to_invoice()
if self.validate_different_vendor() and not self.vendor_approval:
return self._create_notification_action('Notification', 'Terdapat Vendor yang berbeda dengan MD Vendor')
self.check_due()
@@ -817,6 +890,8 @@ class SaleOrder(models.Model):
order.approval_status = 'pengajuan2'
return self._create_approval_notification('Pimpinan')
elif order._requires_approval_margin_manager():
+ self.check_credit_limit()
+ self.check_limit_so_to_invoice()
order.approval_status = 'pengajuan1'
return self._create_approval_notification('Sales Manager')
@@ -923,6 +998,29 @@ class SaleOrder(models.Model):
raise UserError(_("%s is in Blocking Stage, Remaining credit limit is %s, from %s and outstanding %s")
% (rec.partner_id.name, remaining_credit_limit, block_stage, outstanding_amount))
+ def check_limit_so_to_invoice(self):
+ for rec in self:
+ # Ambil jumlah outstanding_amount dan rec.amount_total sebagai current_total
+ outstanding_amount = rec.outstanding_amount
+ current_total = rec.amount_total + outstanding_amount
+
+ # Ambil blocking stage dari partner
+ block_stage = rec.partner_id.parent_id.blocking_stage if rec.partner_id.parent_id else rec.partner_id.blocking_stage or 0
+ is_cbd = rec.partner_id.parent_id.property_payment_term_id.id == 26 if rec.partner_id.parent_id else rec.partner_id.property_payment_term_id.id == 26 or False
+
+ # Ambil jumlah nilai dari SO yang invoice_status masih 'to invoice'
+ so_to_invoice = 0
+ for sale in rec.partner_id.sale_order_ids:
+ if sale.invoice_status == 'to invoice':
+ so_to_invoice = so_to_invoice + sale.amount_total
+ # Hitung remaining credit limit
+ remaining_credit_limit = block_stage - current_total - so_to_invoice
+
+ # Validasi limit
+ if remaining_credit_limit <= 0 and block_stage > 0 and not is_cbd:
+ raise UserError(_("The credit limit for %s will exceed the Blocking Stage if the Sale Order is confirmed. The remaining credit limit is %s, from %s and the outstanding amount is %s.")
+ % (rec.partner_id.name, block_stage - current_total, block_stage, outstanding_amount))
+
def validate_different_vendor(self):
if self.vendor_approval_id.filtered(lambda v: v.state == 'draft'):
draft_names = ", ".join(self.vendor_approval_id.filtered(lambda v: v.state == 'draft').mapped('number'))
@@ -971,6 +1069,8 @@ class SaleOrder(models.Model):
def action_confirm(self):
for order in self:
+ order.check_credit_limit()
+ order.check_limit_so_to_invoice()
if self.validate_different_vendor() and not self.vendor_approval:
return self._create_notification_action('Notification', 'Terdapat Vendor yang berbeda dengan MD Vendor')
@@ -1032,9 +1132,14 @@ class SaleOrder(models.Model):
if self.have_outstanding_invoice:
raise UserError("Invoice harus di Cancel dahulu")
+
+ disallow_states = ['draft', 'waiting', 'confirmed', 'assigned']
+ for picking in self.picking_ids:
+ if picking.state in disallow_states:
+ raise UserError("DO yang draft, waiting, confirmed, atau assigned harus di-cancel oleh Logistik")
for line in self.order_line:
if line.qty_delivered > 0:
- raise UserError("DO harus di-cancel terlebih dahulu.")
+ raise UserError("DO yang done harus di-Return oleh Logistik")
if not self.web_approval:
self.web_approval = 'company'
@@ -1045,8 +1150,24 @@ class SaleOrder(models.Model):
self.due_id = False
if main_parent.use_so_approval:
self.send_notif_to_salesperson(cancel=True)
+ for order in self:
+ if order.amount_total > 30000000:
+ return {
+ 'type': 'ir.actions.act_window',
+ 'name': _('Cancel Reason'),
+ 'res_model': 'cancel.reason.order',
+ 'view_mode': 'form',
+ 'target': 'new',
+ 'context': {'default_request_id': self.id},
+ }
return super(SaleOrder, self).action_cancel()
-
+
+ def confirm_cancel_order(self):
+ """Fungsi ini akan dipanggil oleh wizard setelah alasan pembatalan dipilih"""
+ if self.state != 'cancel':
+ self.state = 'cancel'
+ return super(SaleOrder, self).action_cancel()
+
def validate_partner_invoice_due(self):
parent_id = self.partner_id.parent_id.id
parent_id = parent_id if parent_id else self.partner_id.id
@@ -1078,10 +1199,10 @@ class SaleOrder(models.Model):
return False
def _requires_approval_margin_leader(self):
- return self.total_percent_margin <= 13 and not self.env.user.is_leader
+ return self.total_percent_margin < 15 and not self.env.user.is_leader
def _requires_approval_margin_manager(self):
- return self.total_percent_margin <= 20 and not self.env.user.is_leader and not self.env.user.is_sales_manager
+ return self.total_percent_margin >= 15 and not self.env.user.is_leader and not self.env.user.is_sales_manager
def _create_approval_notification(self, approval_role):
title = 'Warning'
diff --git a/indoteknik_custom/models/sale_order_line.py b/indoteknik_custom/models/sale_order_line.py
index 29a046fa..aed95aab 100644
--- a/indoteknik_custom/models/sale_order_line.py
+++ b/indoteknik_custom/models/sale_order_line.py
@@ -38,11 +38,11 @@ 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=False, compute='_get_desc_updatable')
+ 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:
+ if line.product_id.id != 417724 and line.product_id.id:
line.desc_updatable = False
else:
line.desc_updatable = True
@@ -280,7 +280,7 @@ 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:
+ if line.product_id.id != 417724 and line.product_id.id:
line.desc_updatable = False
else:
line.desc_updatable = True
diff --git a/indoteknik_custom/models/sale_order_multi_uangmuka_penjualan.py b/indoteknik_custom/models/sale_order_multi_uangmuka_penjualan.py
index f9120290..96c2f676 100644
--- a/indoteknik_custom/models/sale_order_multi_uangmuka_penjualan.py
+++ b/indoteknik_custom/models/sale_order_multi_uangmuka_penjualan.py
@@ -68,7 +68,7 @@ class PurchaseOrderMultiUangmukaPenjualan(models.TransientModel):
param_credit = {
'move_id': account_move.id,
- 'account_id': 449, # uang muka penjualan
+ 'account_id': 668, # penerimaan belum alokasi
'partner_id': partner_id,
'currency_id': 12,
'debit': 0,
diff --git a/indoteknik_custom/models/solr/product_template.py b/indoteknik_custom/models/solr/product_template.py
index 87e8370f..8afff6e3 100644
--- a/indoteknik_custom/models/solr/product_template.py
+++ b/indoteknik_custom/models/solr/product_template.py
@@ -76,8 +76,11 @@ class ProductTemplate(models.Model):
('product_id', 'in', template.product_variant_ids.ids),
('location_id', 'in', target_locations),
])
-
- is_in_bu = any(quant.available_quantity > 0 for quant in stock_quant)
+ is_in_bu = False
+ for quant in stock_quant:
+ if quant.product_id.qty_free_bandengan > 0:
+ is_in_bu = True
+ break
cleaned_desc = BeautifulSoup(template.website_description or '', "html.parser").get_text()
website_description = template.website_description if cleaned_desc else ''
diff --git a/indoteknik_custom/models/stock_immediate_transfer.py b/indoteknik_custom/models/stock_immediate_transfer.py
index 35c17192..c2a293f9 100644
--- a/indoteknik_custom/models/stock_immediate_transfer.py
+++ b/indoteknik_custom/models/stock_immediate_transfer.py
@@ -19,6 +19,7 @@ class StockImmediateTransfer(models.TransientModel):
for picking in pickings_to_do:
# picking.send_mail_bills()
# picking.send_koli_to_so()
+ # If still in draft => confirm and assign
if picking.state == 'draft':
picking.action_confirm()
if picking.state != 'assigned':
diff --git a/indoteknik_custom/models/stock_inventory.py b/indoteknik_custom/models/stock_inventory.py
new file mode 100644
index 00000000..12a891de
--- /dev/null
+++ b/indoteknik_custom/models/stock_inventory.py
@@ -0,0 +1,59 @@
+from odoo import models, api, fields
+from odoo.exceptions import UserError
+from datetime import datetime
+import logging
+
+_logger = logging.getLogger(__name__)
+
+
+class StockInventory(models.Model):
+ _inherit = ['stock.inventory']
+ _order = 'id desc'
+ _rec_name = 'number'
+
+ number = fields.Char(string='Document No', index=True, copy=False, readonly=True)
+ adjusment_type = fields.Selection([
+ ('in', 'Adjusment In'),
+ ('out', 'Adjusment Out'),
+ ], string='Adjusments Type', required=True)
+
+ def _generate_number_stock_inventory(self):
+ """Men-generate nomor untuk semua stock inventory yang belum memiliki number."""
+ stock_records = self.env['stock.inventory'].search([('number', '=', False)], order='id asc')
+ for record in stock_records:
+ self._assign_number(record)
+
+ _logger.info('Generate Number Done')
+
+ def _assign_number(self, record):
+ """Menentukan nomor berdasarkan kategori Adjust-In atau Adjust-Out."""
+ name_upper = record.name.upper() if record.name else ""
+
+ if self.adjusment_type == 'out' or "ADJUST OUT" in name_upper or "ADJUST-OUT" in name_upper or "OUT" in name_upper:
+ last_number = self._get_last_sequence("ADJUST/OUT/")
+ record.number = f"ADJUST/OUT/{last_number}"
+ elif self.adjusment_type == 'in' or "ADJUST IN" in name_upper or "ADJUST-IN" in name_upper or "IN" in name_upper:
+ last_number = self._get_last_sequence("ADJUST/IN/")
+ record.number = f"ADJUST/IN/{last_number}"
+ else:
+ record.number = "UNKNOWN" # Jika tidak termasuk kategori
+
+ def _get_last_sequence(self, prefix):
+ """Mengambil nomor terakhir berdasarkan prefix (ADJUST/OUT/ atau ADJUST/IN/) dengan format 00001, 00002, dst."""
+ last_record = self.env['stock.inventory'].search(
+ [("number", "like", f"{prefix}%")], order="number desc", limit=1
+ )
+
+ if last_record and last_record.number:
+ try:
+ last_number = int(last_record.number.split("/")[-1]) # Ambil angka terakhir
+ return str(last_number + 1).zfill(5) # Format jadi 00001, 00002, dst.
+ except ValueError:
+ return "00001" # Jika format tidak valid, mulai dari 00001
+ return "00001" # Jika belum ada data, mulai dari 00001
+
+ @api.model
+ def create(self, vals):
+ order = super(StockInventory, self).create(vals)
+ self._assign_number(order)
+ return order
diff --git a/indoteknik_custom/models/stock_picking.py b/indoteknik_custom/models/stock_picking.py
index df91d451..0699295f 100644
--- a/indoteknik_custom/models/stock_picking.py
+++ b/indoteknik_custom/models/stock_picking.py
@@ -97,7 +97,7 @@ class StockPicking(models.Model):
purchase_representative_id = fields.Many2one('res.users', related='move_lines.purchase_line_id.order_id.user_id', string="Purchase Representative")
carrier_id = fields.Many2one('delivery.carrier', string='Shipping Method')
shipping_status = fields.Char(string='Shipping Status', compute="_compute_shipping_status")
- date_reserved = fields.Datetime(string="Date Reserved", help='Tanggal ter-reserved semua barang nya')
+ date_reserved = fields.Datetime(string="Date Reserved", help='Tanggal ter-reserved semua barang nya', copy=False)
status_printed = fields.Selection([
('not_printed', 'Belum Print'),
('printed', 'Printed')
@@ -123,7 +123,7 @@ class StockPicking(models.Model):
('ready', 'Ready to Ship'),
('done', 'Done'),
('cancel', 'Cancelled'),
- ], string='Status Reserve', readonly=True, tracking=True, help="The current state of the stock picking.")
+ ], string='Status Reserve', tracking=True, copy=False, help="The current state of the stock picking.")
notee = fields.Text(string="Note")
quantity_koli = fields.Float(string="Quantity Koli", copy=False)
@@ -523,18 +523,52 @@ class StockPicking(models.Model):
def check_state_reserve(self):
pickings = self.search([
('state', 'not in', ['cancel', 'draft', 'done']),
+ ('picking_type_code', '=', 'outgoing'),
+ ('name', 'ilike', 'BU/OUT/'),
+ ])
+
+ count = self.search_count([
+ ('state', 'not in', ['cancel', 'draft', 'done']),
('picking_type_code', '=', 'outgoing')
])
for picking in pickings:
- fullfillments = self.env['sales.order.fullfillment'].search([
- ('sales_order_id', '=', picking.sale_id.id)
+ fullfillments = self.env['sales.order.fulfillment.v2'].search([
+ ('sale_order_id', '=', picking.sale_id.id)
+ ])
+
+ picking.state_reserve = 'ready'
+ picking.date_reserved = picking.date_reserved or datetime.datetime.utcnow()
+
+ if any(rec.so_qty != rec.reserved_stock_qty for rec in fullfillments):
+ picking.state_reserve = 'waiting'
+ picking.date_reserved = ''
+
+ self.check_state_reserve_backorder()
+
+ def check_state_reserve_backorder(self):
+ pickings = self.search([
+ ('backorder_id', '!=', False),
+ ('name', 'ilike', 'BU/OUT/'),
+ ('picking_type_code', '=', 'outgoing'),
+ ('state', 'not in', ['cancel', 'draft', 'done'])
+ ])
+
+ count = self.search_count([
+ ('backorder_id', '!=', False),
+ ('picking_type_code', '=', 'outgoing'),
+ ('state', 'not in', ['cancel', 'draft', 'done'])
+ ])
+
+ for picking in pickings:
+ fullfillments = self.env['sales.order.fulfillment.v2'].search([
+ ('sale_order_id', '=', picking.sale_id.id)
])
picking.state_reserve = 'ready'
picking.date_reserved = picking.date_reserved or datetime.datetime.utcnow()
- if any(rec.reserved_from not in ['Inventory On Hand', 'Reserved from stock', 'Free Stock'] for rec in fullfillments):
+ if any(rec.so_qty != rec.reserved_stock_qty for rec in fullfillments):
picking.state_reserve = 'waiting'
picking.date_reserved = ''
@@ -901,6 +935,7 @@ class StockPicking(models.Model):
'res_id': wizard.id,
'target': 'new',
}
+ self.send_mail_bills()
return res
diff --git a/indoteknik_custom/models/uangmuka_pembelian.py b/indoteknik_custom/models/uangmuka_pembelian.py
index 204855d3..ba41f814 100644
--- a/indoteknik_custom/models/uangmuka_pembelian.py
+++ b/indoteknik_custom/models/uangmuka_pembelian.py
@@ -64,7 +64,7 @@ class UangmukaPembelian(models.TransientModel):
param_debit = {
'move_id': account_move.id,
- 'account_id': 401, # uang muka persediaan barang dagang
+ 'account_id': 669, # uang muka persediaan barang dagang
'partner_id': partner_id,
'currency_id': 12,
'debit': self.pay_amt,
diff --git a/indoteknik_custom/models/uangmuka_penjualan.py b/indoteknik_custom/models/uangmuka_penjualan.py
index 5acf604d..a3e95ecd 100644
--- a/indoteknik_custom/models/uangmuka_penjualan.py
+++ b/indoteknik_custom/models/uangmuka_penjualan.py
@@ -74,7 +74,7 @@ class UangmukaPenjualan(models.TransientModel):
# sisa di credit untuk uang muka penjualan, diluar ongkir dan selisih
param_credit = {
'move_id': account_move.id,
- 'account_id': 449, # uang muka penjualan
+ 'account_id': 668, # penerimaan belum alokasi
'partner_id': partner_id,
'currency_id': 12,
'debit': 0,
diff --git a/indoteknik_custom/models/user_company_request.py b/indoteknik_custom/models/user_company_request.py
index af8a86ba..9216e8eb 100644
--- a/indoteknik_custom/models/user_company_request.py
+++ b/indoteknik_custom/models/user_company_request.py
@@ -104,9 +104,9 @@ class UserCompanyRequest(models.Model):
self.user_company_id.active = True
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
- })
+ # new_company = self.env['res.partner'].create({
+ # 'name': self.user_input
+ # })
# self.user_id.parent_id = new_company.id
user.send_company_request_reject_mail()
return super(UserCompanyRequest, self).write(vals)
diff --git a/indoteknik_custom/models/user_pengajuan_tempo_request.py b/indoteknik_custom/models/user_pengajuan_tempo_request.py
index f5261cd4..be4293a0 100644
--- a/indoteknik_custom/models/user_pengajuan_tempo_request.py
+++ b/indoteknik_custom/models/user_pengajuan_tempo_request.py
@@ -7,7 +7,7 @@ class RejectReasonWizard(models.TransientModel):
_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)
+ reason_reject = fields.Text(string='Reason for Rejection', required=True, tracking=True)
def confirm_reject(self):
tempo = self.request_id
@@ -55,7 +55,27 @@ class UserPengajuanTempoRequest(models.Model):
('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')
+ last_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',)
+ reason_reject = fields.Char(string='Reason Reaject', tracking=True, track_visibility='onchange')
+ state_tempo_text = fields.Char(string="Status", compute="_compute_state_tempo_text")
+
+ @api.depends('state_tempo')
+ def _compute_state_tempo_text(self):
+ for record in self:
+ status_mapping = {
+ 'draft': "Menunggu Approve Manager",
+ 'approval_sales': "Menunggu Approve Finance",
+ 'approval_finance': "Menunggu Approve Direktur",
+ 'approval_director': "Approved",
+ 'reject': "Rejected",
+ }
+ record.state_tempo_text = status_mapping.get(record.state_tempo, "Unknown")
# informasi perusahaan
name_tempo = fields.Many2one('res.partner', string='Nama Perusahaan', related='pengajuan_tempo_id.name_tempo', store=True, tracking=True, readonly=False)
@@ -71,7 +91,7 @@ class UserPengajuanTempoRequest(models.Model):
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_duration_origin = fields.Many2one('account.payment.term', string='Durasi Tempo', related='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)
@@ -332,15 +352,15 @@ class UserPengajuanTempoRequest(models.Model):
self.pengajuan_tempo_id.dokumen_tempat_bekerja = self.dokumen_tempat_bekerja
@api.onchange('tempo_duration')
- def _tempo_duration_change(self, vals):
+ def _tempo_duration_change(self):
for tempo in self:
- if tempo.env.user.id not in (7, 377, 12182):
+ if tempo.env.user.id not in (7, 688, 28, 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):
+ if tempo.env.user.id not in (7, 688, 28, 377, 12182):
raise UserError("Limit tempo hanya bisa diubah oleh Sales Manager atau Direktur")
def button_approve(self):
for tempo in self:
@@ -409,6 +429,9 @@ class UserPengajuanTempoRequest(models.Model):
'target': 'new',
'context': {'default_request_id': self.id},
}
+ def button_draft(self):
+ for tempo in self:
+ tempo.state_tempo = tempo.last_state_tempo if tempo.last_state_tempo else 'draft'
def write(self, vals):
is_approve = True if self.state_tempo == 'approval_director' or vals.get('state_tempo') == 'approval_director' else False
@@ -507,10 +530,38 @@ class UserPengajuanTempoRequest(models.Model):
# 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
- })
+ existing_contact = self.env['res.partner'].search([
+ ('parent_id', '=', self.user_company_id.id),
+ ('name', '=', contact_data['name'])
+ ], limit=1)
+
+ if existing_contact:
+ # Pastikan tidak ada duplikasi nama dalam perusahaan yang sama
+ duplicate_check = self.env['res.partner'].search([
+ ('name', '=', contact_data['name']),
+ ('id', '!=', existing_contact.id) # Hindari update yang menyebabkan duplikasi global
+ ], limit=1)
+
+ if not duplicate_check:
+ # Perbarui hanya field yang tidak menyebabkan konflik
+ update_data = {k: v for k, v in contact_data.items() if k != 'name'}
+ existing_contact.write(update_data)
+ else:
+ raise UserError(f"Skipping update for {contact_data['name']} due to existing duplicate.")
+ else:
+ # Pastikan tidak ada partner lain dengan nama yang sama sebelum membuat baru
+ duplicate_check = self.env['res.partner'].search([
+ ('name', '=', contact_data['name'])
+ ], limit=1)
+
+ if duplicate_check:
+ # Jika nama sudah ada tetapi di perusahaan lain, tambahkan nama perusahaan
+ contact_data['name'] = f"{contact_data['name']} ({self.user_company_id.name})"
+
+ 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
@@ -596,10 +647,10 @@ class UserPengajuanTempoRequest(models.Model):
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.property_payment_term_id = self.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
+ self.user_company_id.warning_stage = float(limit_tempo) - (float(limit_tempo)/2)
# Internal Notes
comment = []
diff --git a/indoteknik_custom/models/voucher.py b/indoteknik_custom/models/voucher.py
index 37c97338..101d4bcf 100644
--- a/indoteknik_custom/models/voucher.py
+++ b/indoteknik_custom/models/voucher.py
@@ -59,7 +59,11 @@ class Voucher(models.Model):
show_on_email = fields.Selection([
('user_activation', 'User Activation')
], 'Show on Email')
-
+ account_type = fields.Selection(string='Account Type', default="all", selection=[
+ ('all', "All Account"),
+ ('person', "Account Individu"),
+ ('company', "Account Company"),
+ ])
@api.constrains('description')
def _check_description_length(self):
for record in self:
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}")
diff --git a/indoteknik_custom/security/ir.model.access.csv b/indoteknik_custom/security/ir.model.access.csv
index 83de8bda..18077441 100755
--- a/indoteknik_custom/security/ir.model.access.csv
+++ b/indoteknik_custom/security/ir.model.access.csv
@@ -24,6 +24,7 @@ access_website_categories_homepage,access.website.categories.homepage,model_webs
access_website_categories_lob,access.website.categories.lob,model_website_categories_lob,,1,1,1,1
access_website_categories_management,access.website.categories.management,model_website_categories_management,,1,1,1,1
access_website_categories_management_line,access.website.categories.management.line,model_website_categories_management_line,,1,1,1,1
+access_website_telegram,access.website.telegram,model_website_telegram,,1,1,1,1
access_sales_target,access.sales.target,model_sales_target,,1,1,1,1
access_purchase_outstanding,access.purchase.outstanding,model_purchase_outstanding,,1,1,1,1
access_sales_outstanding,access.sales.outstanding,model_sales_outstanding,,1,1,1,1
@@ -104,6 +105,7 @@ access_purchase_order_multi_update,access.purchase.order.multi_update,model_purc
access_invoice_reklas_penjualan,access.invoice.reklas.penjualan,model_invoice_reklas_penjualan,,1,1,1,1
access_invoice_reklas_penjualan_line,access.invoice.reklas.penjualan.line,model_invoice_reklas_penjualan_line,,1,1,1,1
access_purchase_order_multi_confirm,access.purchase.order.multi_confirm,model_purchase_order_multi_confirm,,1,1,1,1
+access_purchase_order_multi_ask_approval,access.purchase.order.multi_ask_approval,model_purchase_order_multi_ask_approval,,1,1,1,1
access_po_multi_cancel,access.po.multi.cancel,model_po_multi_cancel,,1,1,1,1
access_logbook_sj,access.logbook.sj,model_logbook_sj,,1,1,1,1
access_logbook_sj_line,access.logbook.sj.line,model_logbook_sj_line,,1,1,1,1
@@ -165,4 +167,7 @@ access_reject_reason_wizard,reject.reason.wizard,model_reject_reason_wizard,,1,1
access_confirm_approval_wizard,confirm.approval.wizard,model_confirm_approval_wizard,,1,1,1,0
access_barcode_product,access.barcode.product,model_barcode_product,,1,1,1,1
access_barcoding_product,access.barcoding.product,model_barcoding_product,,1,1,1,1
-access_barcoding_product_line,access.barcoding.product.line,model_barcoding_product_line,,1,1,1,1 \ No newline at end of file
+access_barcoding_product_line,access.barcoding.product.line,model_barcoding_product_line,,1,1,1,1
+access_account_payment_register,access.account.payment.register,model_account_payment_register,,1,1,1,1
+access_stock_inventory,access.stock.inventory,model_stock_inventory,,1,1,1,1
+access_cancel_reason_order,cancel.reason.order,model_cancel_reason_order,,1,1,1,0
diff --git a/indoteknik_custom/views/account_move.xml b/indoteknik_custom/views/account_move.xml
index 36b292e8..17263c3a 100644
--- a/indoteknik_custom/views/account_move.xml
+++ b/indoteknik_custom/views/account_move.xml
@@ -27,6 +27,7 @@
</field>
<field name="invoice_date" position="after">
<field name="sale_id" readonly="1" attrs="{'invisible': [('move_type', '!=', 'out_invoice')]}"/>
+ <field name="purchase_order_id" readonly="1" attrs="{'invisible': [('move_type', '!=', 'in_invoice')]}"/>
</field>
<field name="ref" position="after">
<field name="sale_id" readonly="1" attrs="{'invisible': [('move_type', '!=', 'entry')]}"/>
@@ -137,6 +138,9 @@
{'column_invisible': [('parent.move_type', '!=', 'in_invoice')]}
</attribute>
</field>
+ <field name="product_id" position="before">
+ <field name="line_no" optional="hide"/>
+ </field>
<field name="invoice_incoterm_id" position="after">
<field name="date_terima_tukar_faktur"/>
</field>
diff --git a/indoteknik_custom/views/barcoding_product.xml b/indoteknik_custom/views/barcoding_product.xml
index 566655ff..c7473d39 100644
--- a/indoteknik_custom/views/barcoding_product.xml
+++ b/indoteknik_custom/views/barcoding_product.xml
@@ -8,6 +8,7 @@
<tree default_order="create_date desc">
<field name="product_id"/>
<field name="quantity"/>
+ <field name="type"/>
</tree>
</field>
</record>
@@ -32,11 +33,13 @@
<group>
<group>
<field name="product_id" required="1"/>
- <field name="quantity" required="1"/>
+ <field name="type" required="1"/>
+ <field name="quantity" attrs="{'invisible': [['type', 'in', ('barcoding')]], 'required': [['type', 'not in', ('barcoding')]]}"/>
+ <field name="barcode" attrs="{'invisible': [['type', 'in', ('print')]], 'required': [['type', 'not in', ('print')]]}"/>
</group>
</group>
<notebook>
- <page string="Line">
+ <page string="Line" attrs="{'invisible': [['type', 'in', ('barcoding')]]}">
<field name="barcoding_product_line"/>
</page>
</notebook>
diff --git a/indoteknik_custom/views/customer_commision.xml b/indoteknik_custom/views/customer_commision.xml
index 0b72587e..51172b1c 100644
--- a/indoteknik_custom/views/customer_commision.xml
+++ b/indoteknik_custom/views/customer_commision.xml
@@ -12,6 +12,10 @@
<field name="commision_percent"/>
<field name="commision_amt" readonly="1"/>
<field name="status" readonly="1"/>
+ <field name="payment_status" readonly="1"
+ decoration-success="payment_status == 'payment'"
+ decoration-danger="payment_status == 'pending'"
+ widget="badge"/>
<field name="brand_ids" widget="many2many_tags"/>
</tree>
</field>
@@ -43,6 +47,10 @@
<button name="action_confirm_customer_commision"
string="Confirm" type="object"
options="{}"/>
+ <button name="action_confirm_customer_payment"
+ string="Konfirmasi Pembayaran" type="object"
+ options="{}"
+ attrs="{'invisible': [('payment_status', '==', 'payment')], 'readonly': [('payment_status', '=', 'payment')]}"/>
</header>
<sheet string="Customer Commision">
<div class="oe_button_box" name="button_box"/>
@@ -68,6 +76,7 @@
<field name="brand_ids" widget="many2many_tags"/>
<field name="notification" readonly="1"/>
<field name="status" readonly="1"/>
+ <field name="payment_status" readonly="1" />
<field name="total_dpp"/>
</group>
</group>
diff --git a/indoteknik_custom/views/purchase_order.xml b/indoteknik_custom/views/purchase_order.xml
index a70b2058..36c0db13 100755
--- a/indoteknik_custom/views/purchase_order.xml
+++ b/indoteknik_custom/views/purchase_order.xml
@@ -51,6 +51,9 @@
<field name="approval_status" position="after">
<field name="approval_status_unlock" invisible="True"/>
</field>
+ <field name="partner_id" position="after">
+ <field name="purchase_order_count"/>
+ </field>
<field name="incoterm_id" position="after">
<field name="amount_total_without_service"/>
<field name="delivery_amt"/>
@@ -78,6 +81,9 @@
<field name="product_id" position="attributes">
<attribute name="options">{'no_create': True}</attribute>
</field>
+ <field name="date_planned" position="attributes">
+ <attribute name="invisible">1</attribute>
+ </field>
<field name="product_qty" position="before">
<field name="is_edit_product_qty" readonly="1" optional="hide"/>
<field name="qty_onhand" readonly="1" optional="hide"/>
@@ -103,6 +109,10 @@
<field name="price_vendor" attrs="{'readonly': 1}" optional="hide"/>
</field>
<field name="price_subtotal" position="after">
+ <field name="so_item_margin" attrs="{'readonly': 1}" optional="hide"/>
+ <field name="so_item_percent_margin" attrs="{'readonly': 1}" optional="hide"/>
+ <field name="item_margin" attrs="{'readonly': 1}" optional="hide"/>
+ <field name="item_percent_margin" attrs="{'readonly': 1}" optional="hide"/>
<field name="so_line_id" attrs="{'readonly': 1}" optional="hide"/>
<field name="so_id" attrs="{'readonly': 1}" optional="hide"/>
<field name="indent" optional="hide"/>
@@ -197,7 +207,7 @@
<field name="status_printed" optional="hide"/>
</field>
<field name="partner_id" position="after">
- <field name="store_name"/>
+ <field name="store_name" optional="hide"/>
</field>
</field>
</record>
@@ -290,6 +300,8 @@
<field name="partner_invoice_id"/>
<field name="salesperson_id"/>
<field name="product_id"/>
+ <field name="purchase_price_so"/>
+ <field name="purchase_price_po"/>
<field name="qty_so"/>
<field name="qty_po"/>
<field name="margin_item" optional="hide"/>
@@ -319,6 +331,15 @@
</record>
</data>
<data>
+ <record id="purchase_order_multi_ask_approval_ir_actions_server" model="ir.actions.server">
+ <field name="name">Ask Approval PO</field>
+ <field name="model_id" ref="purchase.model_purchase_order"/>
+ <field name="binding_model_id" ref="purchase.model_purchase_order"/>
+ <field name="state">code</field>
+ <field name="code">action = records.open_form_multi_ask_approval_po()</field>
+ </record>
+ </data>
+ <data>
<record id="purchase_order_multi_create_uangmuka_ir_actions_server" model="ir.actions.server">
<field name="name">Uang Muka</field>
<field name="model_id" ref="purchase.model_purchase_order"/>
diff --git a/indoteknik_custom/views/purchase_order_multi_ask_approval.xml b/indoteknik_custom/views/purchase_order_multi_ask_approval.xml
new file mode 100644
index 00000000..887ac0bd
--- /dev/null
+++ b/indoteknik_custom/views/purchase_order_multi_ask_approval.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<odoo>
+ <data>
+ <record id="view_purchase_order_multi_ask_approval_po_form" model="ir.ui.view">
+ <field name="name">Purchase Order Multi ask_approval</field>
+ <field name="model">purchase.order.multi_ask_approval</field>
+ <field name="arch" type="xml">
+ <form>
+ <sheet>
+ <group>
+ <span>Apakah Anda Yakin Ingin Ask Approval PO Tersebut?</span>
+ </group>
+ </sheet>
+ <footer>
+ <button name="save_multi_ask_approval_po" string="Ask Approval PO" type="object" default_focus="1" class="oe_highlight"/>
+ <button string="Cancel" class="btn btn-secondary" special="cancel" />
+ </footer>
+ </form>
+ </field>
+ </record>
+
+ <record id="action_purchase_order_multi_ask_approval" model="ir.actions.act_window">
+ <field name="name">Purchase Order Multi ask_approval</field>
+ <field name="res_model">purchase.order.multi_ask_approval</field>
+ <field name="type">ir.actions.act_window</field>
+ <field name="view_mode">form</field>
+ <field name="view_id" ref="view_purchase_order_multi_ask_approval_po_form"/>
+ <field name="target">new</field>
+ </record>
+ </data>
+</odoo> \ No newline at end of file
diff --git a/indoteknik_custom/views/report_logbook_sj.xml b/indoteknik_custom/views/report_logbook_sj.xml
index 896594bb..94f6c2ab 100644
--- a/indoteknik_custom/views/report_logbook_sj.xml
+++ b/indoteknik_custom/views/report_logbook_sj.xml
@@ -77,6 +77,16 @@
</field>
</record>
+ <record id="report_logbook_sj_view_search" model="ir.ui.view">
+ <field name="name">report.logbook.sj.search.view</field> <!-- Made the name more descriptive -->
+ <field name="model">report.logbook.sj</field>
+ <field name="arch" type="xml">
+ <search string="Search Report">
+ <field name="sj_number"/>
+ </search>
+ </field>
+ </record>
+
<record id="report_logbook_sj_action" model="ir.actions.act_window">
<field name="name">Report Logbook SJ</field>
<field name="type">ir.actions.act_window</field>
diff --git a/indoteknik_custom/views/res_partner.xml b/indoteknik_custom/views/res_partner.xml
index bd664890..af5e0db3 100644
--- a/indoteknik_custom/views/res_partner.xml
+++ b/indoteknik_custom/views/res_partner.xml
@@ -68,6 +68,7 @@
<field name="vat" position="after">
<field name="email_finance" widget="email"/>
<field name="email_sales" widget="email"/>
+ <field name="telegram_id"/>
<field name="use_so_approval" attrs="{'invisible': [('parent_id', '!=', False), ('company_type', '!=', 'company')]}" />
<field name="use_only_ready_stock" attrs="{'invisible': [('parent_id', '!=', False), ('company_type', '!=', 'company')]}" />
<field name="web_role" attrs="{'invisible': ['|', ('parent_id', '=', False), ('company_type', '=', 'company')]}" />
diff --git a/indoteknik_custom/views/res_users.xml b/indoteknik_custom/views/res_users.xml
index 9553bb91..5b35f9c4 100644
--- a/indoteknik_custom/views/res_users.xml
+++ b/indoteknik_custom/views/res_users.xml
@@ -236,6 +236,7 @@
<tr><td style="padding-bottom: 16px;"><b>Pembayaran Lengkap:</b> Pilih metode pembayaran yang sesuai dengan kebutuhan Anda, baik transfer bank, VA, kartu kredit, atau pembayaran tempo.</td></tr>
<tr><td style="padding-bottom: 16px;"><b>Pelacakan Pengiriman:</b> Lacak status pengiriman pesanan Anda secara real-time.</td></tr>
<tr><td style="padding-bottom: 16px;">Untuk memulai transaksi, silakan login Kembali menggunakan akun Anda di <a href="https://indoteknik.com/login">Indoteknik.com</a></td></tr>
+ <tr><td style="padding-bottom: 16px;">Gunakan kode voucher berikut untuk mendapatkan diskon belanja hingga 10 juta: <strong>${object.get_voucher_code('switch_account')}</strong></td></tr>
<tr><td style="padding-bottom: 16px;">Kami sangat senang dapat melayani Anda. Jika ada pertanyaan atau membutuhkan bantuan, jangan ragu untuk menghubungi tim layanan Customer kami di Whatsapp <a href="https://wa.me/6281717181922">0817-1718-1922</a> atau <a href="mailto:sales@indoteknik.com">sales@indoteknik.com</a></td></tr>
<tr><td style="padding-bottom: 2px;"><b>Hormat kami,</b></td></tr>
@@ -299,6 +300,7 @@
<tr><td style="padding-bottom: 16px;">Selamat! Akun bisnis Anda di indoteknik.com sekarang sudah resmi menjadi PKP dari yang sebelumnya Non-PKP.</td></tr>
<tr><td style="padding-bottom: 16px;">Jangan lupa untuk mengecek kembali semua data perusahaan kamu, ya. Pastikan NPWP dan informasi Perusahaan lainnya sudah kamu isi dengan benar.</td></tr>
+ <tr><td style="padding-bottom: 16px;">Gunakan kode voucher berikut untuk mendapatkan diskon belanja hingga 10 juta: <strong>${object.get_voucher_code('switch_account')}</strong></td></tr>
<tr><td style="padding-bottom: 16px;">Kamu juga dapat mengubah informasi perusahaan dengan mengunjungi profil atau <a href="https://indoteknik.com/my/profile">klik disini</a></td></tr>
<tr><td style="padding-bottom: 2px;">Industrial Supply &amp; Solutions</td></tr>
diff --git a/indoteknik_custom/views/sale_order.xml b/indoteknik_custom/views/sale_order.xml
index 4d31b072..8158774b 100755
--- a/indoteknik_custom/views/sale_order.xml
+++ b/indoteknik_custom/views/sale_order.xml
@@ -111,7 +111,7 @@
<field name="desc_updatable" invisible="1"/>
</xpath>
<xpath expr="//form/sheet/notebook/page/field[@name='order_line']/tree/field[@name='name']" position="attributes">
- <attribute name="attrs">
+ <attribute name="modifiers">
{'readonly': [('desc_updatable', '=', False)]}
</attribute>
</xpath>
@@ -286,6 +286,31 @@
</page>
</field>
</record>
+ <!-- Wizard for Reject Reason -->
+ <record id="view_cancel_reason_order_form" model="ir.ui.view">
+ <field name="name">cancel.reason.order.form</field>
+ <field name="model">cancel.reason.order</field>
+ <field name="arch" type="xml">
+ <form string="Cancel Reason">
+ <group>
+ <field name="reason_cancel" widget="selection"/>
+ <field name="attachment_bukti" widget="many2many_binary" required="1"/>
+ <field name="nomor_so_pengganti" attrs="{'invisible': [('reason_cancel', '!=', 'ganti_quotation')]}"/>
+ </group>
+ <footer>
+ <button string="Confirm" type="object" name="confirm_reject" class="btn-primary"/>
+ <button string="Cancel" class="btn-secondary" special="cancel"/>
+ </footer>
+ </form>
+ </field>
+ </record>
+
+ <record id="action_cancel_reason_order" model="ir.actions.act_window">
+ <field name="name">Cancel Reason</field>
+ <field name="res_model">cancel.reason.order</field>
+ <field name="view_mode">form</field>
+ <field name="target">new</field>
+ </record>
</data>
<data>
<record id="sale_order_tree_view_inherit" model="ir.ui.view">
@@ -299,6 +324,7 @@
<field name="payment_type" optional="hide"/>
<field name="payment_status" optional="hide"/>
<field name="pareto_status" optional="hide"/>
+ <field name="shipping_method_picking" optional="hide"/>
</field>
</field>
</record>
diff --git a/indoteknik_custom/views/stock_inventory.xml b/indoteknik_custom/views/stock_inventory.xml
new file mode 100644
index 00000000..db85f05c
--- /dev/null
+++ b/indoteknik_custom/views/stock_inventory.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<odoo>
+ <!-- Form View: Tambahkan field 'number' setelah lokasi -->
+ <record id="view_stock_inventory_form_inherit" model="ir.ui.view">
+ <field name="name">stock.inventory.form.inherit</field>
+ <field name="model">stock.inventory</field>
+ <field name="inherit_id" ref="stock.view_inventory_form"/>
+ <field name="arch" type="xml">
+ <xpath expr="//field[@name='location_ids']" position="after">
+ <field name="number" readonly="1"/>
+ <field name="adjusment_type" />
+ </xpath>
+ </field>
+ </record>
+
+ <!-- Tree View: Tambahkan field 'number' setelah tanggal -->
+ <record id="view_stock_inventory_tree_inherit" model="ir.ui.view">
+ <field name="name">stock.inventory.tree.inherit</field>
+ <field name="model">stock.inventory</field>
+ <field name="inherit_id" ref="stock.view_inventory_tree"/>
+ <field name="arch" type="xml">
+ <xpath expr="//field[@name='date']" position="after">
+ <field name="number"/>
+ </xpath>
+ </field>
+ </record>
+
+</odoo>
diff --git a/indoteknik_custom/views/stock_picking.xml b/indoteknik_custom/views/stock_picking.xml
index 016fbf17..03fc8f87 100644
--- a/indoteknik_custom/views/stock_picking.xml
+++ b/indoteknik_custom/views/stock_picking.xml
@@ -89,9 +89,9 @@
<field name="partner_id" position="after">
<field name="real_shipping_id"/>
</field>
- <field name="product_uom_qty" position="attributes">
+ <!-- <field name="product_uom_qty" position="attributes">
<attribute name="attrs">{'readonly': [('parent.picking_type_code', '=', 'incoming')]}</attribute>
- </field>
+ </field> -->
<field name="date_done" position="after">
<field name="arrival_time"/>
</field>
diff --git a/indoteknik_custom/views/user_pengajuan_tempo.xml b/indoteknik_custom/views/user_pengajuan_tempo.xml
index 33ad91cf..7f1faa41 100644
--- a/indoteknik_custom/views/user_pengajuan_tempo.xml
+++ b/indoteknik_custom/views/user_pengajuan_tempo.xml
@@ -269,7 +269,7 @@
<field name="subject">Pengajuan Tempo Harus di Periksa!</field>
<field name="email_from">"Indoteknik.com" &lt;noreply@indoteknik.com&gt;</field>
<field name="reply_to">sales@indoteknik.com</field>
- <field name="email_to">widyariyanti97@gmail.com, stephan@indoteknik.co.id</field>
+ <field name="email_to">finance@indoteknik.co.id, stephan@indoteknik.co.id, sapiabon768@gmail.com</field>
<!-- <field name="email_to">sapiabon768@gmail.com</field>-->
<field name="body_html" type="html">
<table border="0" cellpadding="0" cellspacing="0" style="padding-top: 16px; background-color: #F1F1F1; font-family:Inter, Helvetica, Verdana, Arial,sans-serif; line-height: 24px; color: #454748; width: 100%; border-collapse:separate;">
diff --git a/indoteknik_custom/views/user_pengajuan_tempo_request.xml b/indoteknik_custom/views/user_pengajuan_tempo_request.xml
index bb8262c9..7063231b 100644
--- a/indoteknik_custom/views/user_pengajuan_tempo_request.xml
+++ b/indoteknik_custom/views/user_pengajuan_tempo_request.xml
@@ -10,7 +10,17 @@
<field name="create_date"/>
<field name="tempo_duration" attrs="{'readonly': [('state_tempo', '=', 'approval_director')]}"/>
<field name="tempo_limit" attrs="{'readonly': [('state_tempo', '=', 'approval_director')]}" placeholder="Contoh format, misalnya '10000000'" widget="monetary" options="{'currency_field': 'currency_id'}"/>
- <field name="state_tempo" decoration-success="state_tempo == 'approval_director'" decoration-danger="state_tempo == 'reject'" widget="badge" optional="show"/>
+<!-- <field name="state_tempo"-->
+<!-- decoration-danger="state_tempo == 'reject'"-->
+<!-- decoration-warning="state_tempo in ('draft', 'approval_sales', 'approval_finance')"-->
+<!-- decoration-success="state_tempo == 'approval_director'">-->
+<!-- <tree>-->
+<!-- <field name="state_tempo" invisible="1"/>-->
+<!-- <field name="state_tempo_text" string="Status"/>-->
+<!-- </tree>-->
+<!-- </field>-->
+ <field name="state_tempo" invisible="1"/>
+ <field name="state_tempo_text" decoration-success="state_tempo_text == 'Approved'" decoration-danger="state_tempo_text == 'Rejected'" widget="badge" optional="show"/>
</tree>
</field>
</record>
@@ -30,7 +40,11 @@
string="Reject"
attrs="{'invisible': [('state_tempo', 'in', ['approval_director','reject'])]}"
type="object"
- groups="purchase.group_purchase_manager"
+ class="oe_highlight"/>
+ <button name="button_draft"
+ string="Reset to Draft"
+ attrs="{'invisible': [('state_tempo', '!=', 'reject')]}"
+ type="object"
class="oe_highlight"/>
<field name="state_tempo" widget="statusbar"
statusbar_visible="draft,approval_sales,approval_finance,approval_director"
diff --git a/indoteknik_custom/views/voucher.xml b/indoteknik_custom/views/voucher.xml
index 29d0ad4b..ae958f05 100755
--- a/indoteknik_custom/views/voucher.xml
+++ b/indoteknik_custom/views/voucher.xml
@@ -35,6 +35,7 @@
<field name="limit" required="1"/>
<field name="limit_user" required="1"/>
<field name="apply_type" required="1" />
+ <field name="account_type" required="1" />
<field name="show_on_email" />
<field name="excl_pricelist_ids" widget="many2many_tags" domain="[('id', 'in', [4, 15037, 15038, 15039, 17023, 17024, 17025, 17026,17027])]"/>
</group>
diff --git a/indoteknik_custom/views/website_telegram.xml b/indoteknik_custom/views/website_telegram.xml
new file mode 100644
index 00000000..d8590fc0
--- /dev/null
+++ b/indoteknik_custom/views/website_telegram.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<odoo>
+ <data>
+ <record id="website_telegram_action" model="ir.actions.act_window">
+ <field name="name">Channel Telegram</field>
+ <field name="res_model">website.telegram</field>
+ <field name="view_mode">tree,form</field>
+ </record>
+
+ <record id="website_telegram_tree" model="ir.ui.view">
+ <field name="name">website.telegram.tree</field>
+ <field name="model">website.telegram</field>
+ <field name="arch" type="xml">
+ <tree string="Channel List">
+ <field name="tittle"/>
+ <field name="about"/>
+ <field name="user_id"/>
+ <button name="test_send" type="object" icon="fa-paper-plane" string="Send Test"/>
+<!-- <button name="create_channel" type="object" icon="fa-paper-plane" string="Create Channel"/>-->
+<!-- <button name="receive_messages" type="object" icon="fa-paper-plane" string="GET Test"/>-->
+ </tree>
+ </field>
+ </record>
+
+ <record id="website_telegram_form" model="ir.ui.view">
+ <field name="name">website.telegram.form</field>
+ <field name="model">website.telegram</field>
+ <field name="arch" type="xml">
+ <form create="0">
+ <sheet>
+ <group>
+ <group>
+ <field name="tittle"/>
+ <field name="about"/>
+ <field name="user_id" widget="many2many_tags"/>
+ </group>
+ </group>
+ </sheet>
+ </form>
+ </field>
+ </record>
+
+ <record id="ir_actions_server_website_telegram_sync_to_solr" model="ir.actions.server">
+ <field name="name">Sync to solr</field>
+ <field name="model_id" ref="indoteknik_custom.model_website_telegram"/>
+ <field name="binding_model_id" ref="indoteknik_custom.model_website_telegram"/>
+ <field name="state">code</field>
+ <field name="code">model.action_sync_to_solr()</field>
+ </record>
+
+ <menuitem
+ id="website_telegram"
+ name="Channel Telegram"
+ parent="website_sale.menu_orders"
+ sequence="1"
+ action="website_telegram_action"
+ />
+ </data>
+</odoo>