diff options
43 files changed, 3264 insertions, 104 deletions
diff --git a/indoteknik_api/controllers/api_v1/flash_sale.py b/indoteknik_api/controllers/api_v1/flash_sale.py index 00b1f2e0..6c4ad8c0 100644 --- a/indoteknik_api/controllers/api_v1/flash_sale.py +++ b/indoteknik_api/controllers/api_v1/flash_sale.py @@ -20,6 +20,7 @@ class FlashSale(controller.Controller): query = [ ('pricelist_id', '=', pricelist.id) ] + formatted_end_date = pricelist.end_date.strftime('%Y-%m-%dT%H:%M:%S.%f')[:-3] + 'Z' if pricelist.end_date else None data.append({ 'pricelist_id': pricelist.id, 'option': pricelist.flashsale_option, @@ -29,6 +30,7 @@ class FlashSale(controller.Controller): 'banner_mobile': request.env['ir.attachment'].api_image('product.pricelist', 'banner_mobile', pricelist.id), 'banner_top': request.env['ir.attachment'].api_image('product.pricelist', 'banner_top', pricelist.id), 'duration': pricelist._remaining_time_in_second(), + 'end_date': formatted_end_date, 'product_total': request.env['product.pricelist.item'].search_count(query), }) return self.response(data) diff --git a/indoteknik_api/controllers/api_v1/invoice.py b/indoteknik_api/controllers/api_v1/invoice.py index 4937e8dd..4bd3746c 100644 --- a/indoteknik_api/controllers/api_v1/invoice.py +++ b/indoteknik_api/controllers/api_v1/invoice.py @@ -1,7 +1,7 @@ from .. import controller from odoo import http from odoo.http import request - +from odoo import fields class Invoice(controller.Controller): PREFIX = '/api/v1/' @@ -15,6 +15,7 @@ class Invoice(controller.Controller): 'name': [], 'limit': ['default:0', 'number'], 'offset': ['default:0', 'number'], + 'status': [], }) limit = params['value']['limit'] offset = params['value']['offset'] @@ -27,6 +28,11 @@ class Invoice(controller.Controller): ('state', '=', 'posted'), ('partner_id', 'in', partner_child_ids) ] + domain_orders = [ + ('invoice_status', '!=', 'invoiced'), + ('state', '=', 'sale'), + ('partner_id', 'in', partner_child_ids) + ] if params['value']['name']: name = params['value']['name'].replace(' ', '%') domain += [ @@ -34,10 +40,25 @@ class Invoice(controller.Controller): ('name', 'ilike', '%'+ name +'%'), ('ref', 'ilike', '%'+ name +'%') ] + if params['value']['status']: + if params['value']['status'] == '1': + domain += [('payment_state', '=', 'not_paid'), ('invoice_date_due', '<', fields.Date.today())] + elif params['value']['status'] == '2': + domain += [('payment_state', '=', 'not_paid'), ('invoice_date_due', '>', fields.Date.today())] + elif params['value']['status'] == '3': + domain += [('payment_state', '=', 'paid')] + elif params['value']['status'] == '0': + domain = domain + elif params['value']['status'] == '4': + domain += [('payment_state', '=', 'not_paid')] + invoices = request.env['account.move'].search(domain, offset=offset, limit=limit) + sale_orders = request.env['sale.order'].search(domain_orders, offset=offset, limit=limit) data = { 'invoice_total': request.env['account.move'].search_count(domain), - 'invoices': [request.env['account.move'].api_v1_single_response(x) for x in invoices] + 'invoices': [request.env['account.move'].api_v1_single_response(x) for x in invoices], + 'sale_order_total': request.env['sale.order'].search_count(domain_orders), + 'sale_orders': [request.env['sale.order'].api_v1_single_response(x) for x in sale_orders] } return self.response(data) diff --git a/indoteknik_api/controllers/api_v1/partner.py b/indoteknik_api/controllers/api_v1/partner.py index bbca471b..885cf3ec 100644 --- a/indoteknik_api/controllers/api_v1/partner.py +++ b/indoteknik_api/controllers/api_v1/partner.py @@ -1,7 +1,10 @@ from .. import controller from odoo import http from odoo.http import request - +from odoo import fields +import json +import base64 +import mimetypes class Partner(controller.Controller): _name = 'res.partner' @@ -135,6 +138,8 @@ class Partner(controller.Controller): 'npwp': [], 'alamat_lengkap_text': [], 'street': [], + 'email': [], + 'mobile': [] }) # Mengambil id_user dari request @@ -208,6 +213,32 @@ class Partner(controller.Controller): }) return self.response(data) + + @http.route(prefix + 'partner/payment_term', auth='public', methods=['GET', 'OPTIONS']) + @controller.Controller.must_authorized() + def get_partner_payment_term(self): + partner_industry = request.env['account.payment.term'].search([]) + data = [] + for industry in partner_industry: + if 'tempo' in industry.name.lower(): + data.append({ + 'id': industry.id, + 'name': industry.name + }) + + return self.response(data) + + @http.route(prefix + 'partner/detail-tempo/<id>', auth='public', methods=['GET', 'OPTIONS']) + @controller.Controller.must_authorized() + def get_partner_detail_tempo(self, **kw): + params = self.get_request_params(kw, { + 'id': ['required', 'number'] + }) + pengajuan_tempo = request.env['user.pengajuan.tempo'].search([('name_tempo', '=', params['value']['id'])], limit=1) + if not pengajuan_tempo: + return self.response(code=404, description='pengajuan tempo not found') + pengajuan_tempo = request.env['res.partner'].api_single_response(pengajuan_tempo) + return self.response(pengajuan_tempo) @http.route(prefix + 'check/<partner_id>/tempo', auth='public', methods=['GET', 'OPTIONS']) @controller.Controller.must_authorized() @@ -222,18 +253,318 @@ class Partner(controller.Controller): if any(line.days == 0 for line in partner.property_payment_term_id.line_ids): return self.response(code=402, description='Partner not tempo') - - result_tempo = sum(m.amount_total_signed for m in request.env['account.move'].search([('partner_id', '=', partner.id), ('payment_state', '=', 'not_paid'), ('state', '=', 'posted')])) - + + domain_result_tempo = [('partner_id', '=', partner.id), ('payment_state', '=', 'not_paid'), ('state', '=', 'posted')] + domain_result_jatuh_tempo = [('partner_id', '=', partner.id), ('payment_state', '=', 'not_paid'), ('state', '=', 'posted'), ('invoice_date_due', '<', fields.Date.today())] + domain_orders = [('partner_id', '=', partner.id), ('invoice_status', '!=', 'invoiced'), ('state', '=', 'sale')] + + result_tempo = sum(m.amount_total_signed for m in request.env['account.move'].search(domain_result_tempo)) + result_tempo_total = request.env['account.move'].search_count(domain_result_tempo) + result_jatuh_tempo = sum(m.amount_total_signed for m in request.env['account.move'].search(domain_result_jatuh_tempo)) + result_jatuh_tempo_total = request.env['account.move'].search_count(domain_result_jatuh_tempo) + orders = request.env['sale.order'].search(domain_orders) + orders_total = request.env['sale.order'].search_count(domain_orders) + + total_amount = sum(order.amount_total for order in orders) + remaining_limit = partner.blocking_stage - result_tempo if partner.active_limit else None data = { 'name': partner.name, + 'payment_term': partner.property_payment_term_id.name, 'amount_due': result_tempo, + 'amount_due_total': result_tempo_total, + 'amount_jatuh_tempo_total': result_jatuh_tempo_total, + 'amount_jatuh_tempo': result_jatuh_tempo, + 'amount_due_sale': total_amount, + 'amount_due_sale_total': orders_total, 'remaining_limit': remaining_limit } - + + return self.response(data) + + @http.route(prefix + 'check/<partner_id>/tempo_progress', auth='public', methods=['GET', 'OPTIONS']) + @controller.Controller.must_authorized() + def get_check_tempo_partner_progres(self, **kw): + partner_id = int(kw.get('partner_id')) + partner = request.env['res.partner'].search([('id', '=', partner_id)], limit=1) + pengajuan_tempo = request.env['user.pengajuan.tempo'].search([('name_tempo', '=', partner.id)], limit=1) + if not pengajuan_tempo: + return self.response(code=404, description='Partner not found') + + data = True if pengajuan_tempo.id else False return self.response(data) + @http.route(prefix + 'partner/pengajuan_tempo', auth='public', methods=['POST'], csrf=False) + @controller.Controller.must_authorized() + def write_pengajuan_tempo(self, **kw): + id = int(kw.get('partner_id')) + user_id = int(kw.get('user_id')) + tempo_request = True if kw.get('tempo_request') == 'true' else False + pengajuan_tempo = request.env['user.pengajuan.tempo'].search([('name_tempo', '=', user_id)], limit=1) + user = request.env['res.partner'].search([('id', '=', user_id)], limit=1) + company_name = kw.get('name', pengajuan_tempo.name_tempo.name) + partner_id = request.env['res.partner'].search([('name', 'like', company_name)], limit=1) + user_account = self.get_user_by_email(user.email) + params = self.get_request_params(kw, { + + # informasi perusahaan + # 'name': ['required', 'alias:name_tempo'], + 'industryId': ['alias:industry_id_tempo'], + 'street': ['alias:street_tempo'], + 'state': ['alias:state_id_tempo'], + 'city': ['alias:city_id_tempo'], + 'district': ['alias:district_id_tempo'], + 'subDistrict': ['alias:subDistrict_id_tempo'], + 'zip': ['alias:zip_tempo'], + 'mobile': ['alias:mobile_tempo'], + 'bankName': ['alias:bank_name_tempo'], + 'accountName': ['alias:account_name_tempo'], + 'accountNumber': ['alias:account_number_tempo'], + 'website': ['alias:website_tempo'], + 'estimasi': ['alias:estimasi_tempo'], + 'portal': ['alias:portal'], + 'bersedia': ['alias:bersedia'], + 'tempoDuration': ['alias:tempo_duration'], + 'tempoLimit': ['alias:tempo_limit'], + + # informasi perusahaan + 'direkturTittle': ['alias:direktur_tittle'], + 'direkturName': ['alias:direktur_name'], + 'direkturMobile': ['alias:direktur_mobile'], + 'direkturEmail': ['alias:direktur_email'], + 'purchasingTittle': ['alias:purchasing_tittle'], + 'purchasingName': ['alias:purchasing_name'], + 'purchasingMobile': ['alias:purchasing_mobile'], + 'purchasingEmail': ['alias:purchasing_email'], + 'financeTittle': ['alias:finance_tittle'], + 'financeName': ['alias:finance_name'], + 'financeMobile': ['alias:finance_mobile'], + 'financeEmail': ['alias:finance_email'], + + # Pengiriman + 'PICTittle': ['alias:pic_tittle'], + 'PICName': ['alias:pic_name'], + 'streetPengiriman': ['alias:street_pengiriman'], + 'statePengiriman': ['alias:state_id_pengiriman'], + 'cityPengiriman': ['alias:city_id_pengiriman'], + 'districtPengiriman': ['alias:district_id_pengiriman'], + 'subDistrictPengiriman': ['alias:subDistrict_id_pengiriman'], + 'zipPengiriman': ['alias:zip_pengiriman'], + 'invoicePicTittle': ['alias:invoice_pic_tittle'], + 'invoicePic': ['alias:invoice_pic'], + 'streetInvoice': ['alias:street_invoice'], + 'stateInvoice': ['alias:state_id_invoice'], + 'cityInvoice': ['alias:city_id_invoice'], + 'districtInvoice': ['alias:district_id_invoice'], + 'subDistrictInvoice': ['alias:subDistrict_id_invoice'], + 'zipInvoice': ['alias:zip_invoice'], + 'isSameAddrees':['alias:is_same_address'], + 'isSameAddreesStreet':['alias:is_same_address_street'], + }) + + # # Konversi nilai 'true' ke boolean True + # is_same_address = kw.get('isSameAddrees', 'false').lower() == 'true' + # is_same_address_street = kw.get('isSameAddreesStreet', 'false').lower() == 'true' + # + # # Tambahkan nilai yang dikonversi ke params + # if 'isSameAddress' in kw: + # params['value']['is_same_address'] = is_same_address + # if 'is_same_address_street' in kw: + # params['value']['is_same_address_street'] = is_same_address_street + + if not params['valid']: + return self.response(code=400, description=params) + if params['value']['portal']: + if params['value']['portal'] == 'ada': + params['value']['portal'] = True + else: + params['value']['portal'] = False + # Filter data baru yang dikirim (non-kosong, boolean False tetap masuk) + new_data = {key: value for key, value in params['value'].items() if value != ''} + + if pengajuan_tempo: + # Jika pengajuan_tempo sudah ada, hanya write data baru yang non-kosong + pengajuan_tempo.write(new_data) + else: + # Jika belum ada, buat record baru + pengajuan_tempo = request.env['user.pengajuan.tempo'].create(new_data) + pengajuan_tempo.partner_id = user_id + + if partner_id: + pengajuan_tempo.name_tempo = partner_id + + form_supplier_data = kw.get('formSupplier', False) + + if form_supplier_data: + try: + form_supplier_data = json.loads(form_supplier_data) + + supplier_ids_to_add = [] + for item in form_supplier_data: + supplier_name = item.get("supplier") + pic_name = item.get("pic") + phone = item.get("telepon") + tempo_duration = item.get("durasiTempo") + credit_limit = item.get("creditLimit") + + new_data = { + 'name_supplier': supplier_name, + 'pic_name': pic_name, + 'phone': phone, + 'tempo_duration': tempo_duration, + 'credit_limit': credit_limit, + } + new_supplier_data = request.env['user.pengajuan.tempo.line'].create(new_data) + + supplier_ids_to_add.append(new_supplier_data.id) + + pengajuan_tempo.write({'supplier_ids': [(6, 0, supplier_ids_to_add)]}) + + except json.JSONDecodeError: + return http.Response(status=400, json_body={'error': 'Invalid JSON format for formSupplier'}) + category_produk_ids = kw.get('categoryProduk', False) + category_ids = '' + if category_produk_ids: + category_ids = list(map(int, category_produk_ids.split(','))) + pengajuan_tempo.category_produk_ids = [(6, 0, category_ids)] + + tukar_invoice_input = kw.get('tukarInvoiceInput') + if tukar_invoice_input: + pengajuan_tempo.tukar_invoice = tukar_invoice_input + + tukar_invoice_input_pembayaran = kw.get('tukarInvoiceInputPembayaran') + if tukar_invoice_input_pembayaran: + pengajuan_tempo.jadwal_bayar = tukar_invoice_input_pembayaran + + dokumen_kirim = [ + 'Surat Tanda Terima Barang (STTB)', + 'Good Receipt (GR)', + 'Surat Terima Barang (STB)', + 'Lembar Penerimaan Barang (LPB)' + ] + + dokumen_kirim_barang_ids = kw.get('dokumenPengiriman') + dokumen_kirim_input = kw.get('dokumenKirimInput', '') + dokumen_kirim_barang_input = kw.get('dokumenPengirimanInput', '') + dokumen_kirim_barang = [] + + if dokumen_kirim_barang_ids: + dokumen_kirim_ids = list(map(int, dokumen_kirim_barang_ids.split(','))) + dokumen_kirim_barang = [dokumen_kirim[i] for i in dokumen_kirim_ids if 0 <= i < len(dokumen_kirim)] + if dokumen_kirim_input: + input_items = [item.strip() for item in dokumen_kirim_input.split(',')] + dokumen_kirim_barang.extend(item for item in input_items if item and item not in dokumen_kirim_barang) + pengajuan_tempo.dokumen_kirim_input = dokumen_kirim_input + if dokumen_kirim_barang: + pengajuan_tempo.dokumen_pengiriman = ', '.join(dokumen_kirim_barang) + if dokumen_kirim_barang_input: + pengajuan_tempo.dokumen_pengiriman_input = dokumen_kirim_barang_input + + dokumen = [ + 'Invoice Pembelian', + 'Surat Jalan', + 'Berita Acara Serah Terima (BAST)', + 'Faktur Pajak', + 'Good Receipt (GR)' + ] + + dokumen_invoice = kw.get('dokumenPengirimanInvoice', '') + if dokumen_invoice: + pengajuan_tempo.dokumen_invoice = dokumen_invoice + user_tempo_request = [] + if tempo_request: + user_tempo_request = request.env['user.pengajuan.tempo.request'].create({ + 'user_id': id, + 'pengajuan_tempo_id': pengajuan_tempo.id, + 'user_company_id': partner_id.id, + 'tempo_duration': pengajuan_tempo.tempo_duration.id, + 'tempo_limit': pengajuan_tempo.tempo_limit, + }) + + form_dokumen_data = kw.get('formDocs', False) + if form_dokumen_data: + try: + form_dokumen = json.loads(form_dokumen_data) + + for dokumen in form_dokumen: + if dokumen['details']['base64'] != '': + mimetype, _ = mimetypes.guess_type(dokumen['details']['name']) + mimetype = mimetype or 'application/octet-stream' + data = base64.b64decode(dokumen['details']['base64']) + sppkp_attachment = request.env['ir.attachment'].create({ + 'name': dokumen['details']['name'], + 'type': 'binary', + 'datas': base64.b64encode(data), + 'res_model': 'user.pengajuan.tempo', + 'res_id': pengajuan_tempo.id, + 'mimetype': mimetype + }) + + if dokumen['documentName'] == 'dokumenNib': + pengajuan_tempo.dokumen_nib = [(6, 0, [sppkp_attachment.id])] + + elif dokumen['documentName'] == 'dokumenSiup': + pengajuan_tempo.dokumen_siup = [(6, 0, [sppkp_attachment.id])] + + elif dokumen['documentName'] == 'dokumenTdp': + pengajuan_tempo.dokumen_tdp = [(6, 0, [sppkp_attachment.id])] + + elif dokumen['documentName'] == 'dokumenSkdp': + pengajuan_tempo.dokumen_skdp = [(6, 0, [sppkp_attachment.id])] + + elif dokumen['documentName'] == 'dokumenSkt': + pengajuan_tempo.dokumen_skt = [(6, 0, [sppkp_attachment.id])] + + elif dokumen['documentName'] == 'dokumenNpwp': + pengajuan_tempo.dokumen_npwp = [(6, 0, [sppkp_attachment.id])] + + elif dokumen['documentName'] == 'dokumenSppkp': + pengajuan_tempo.dokumen_sppkp = [(6, 0, [sppkp_attachment.id])] + + elif dokumen['documentName'] == 'dokumenAktaPerubahan': + pengajuan_tempo.dokumen_akta_perubahan = [(6, 0, [sppkp_attachment.id])] + + elif dokumen['documentName'] == 'dokumenKtpDirut': + pengajuan_tempo.dokumen_ktp_dirut = [(6, 0, [sppkp_attachment.id])] + + elif dokumen['documentName'] == 'dokumenAktaPendirian': + pengajuan_tempo.dokumen_akta_pendirian = [(6, 0, [sppkp_attachment.id])] + + elif dokumen['documentName'] == 'dokumenLaporanKeuangan': + pengajuan_tempo.dokumen_laporan_keuangan = [(6, 0, [sppkp_attachment.id])] + + elif dokumen['documentName'] == 'dokumenFotoKantor': + pengajuan_tempo.dokumen_foto_kantor = [(6, 0, [sppkp_attachment.id])] + + elif dokumen['documentName'] == 'dokumenTempatBekerja': + pengajuan_tempo.dokumen_tempat_bekerja = [(6, 0, [sppkp_attachment.id])] + + formatted_text = ''.join([' ' + char if char.isupper() and i != 0 else char for i, char in + enumerate(dokumen['documentName'])]) + teks = formatted_text.strip().title() + pengajuan_tempo.message_post(body=teks, attachment_ids=[sppkp_attachment.id]) + if tempo_request: + user_tempo_request.message_post(body=teks, attachment_ids=[sppkp_attachment.id]) + + + except json.JSONDecodeError: + return http.Response(status=400, json_body={'error': 'Invalid JSON format for formDokumen'}) + + if tempo_request: + # pengajuan_tempo.user_id = id + template = pengajuan_tempo.env.ref('indoteknik_custom.mail_template_res_user_company_request_tempo_review') + template.send_mail(pengajuan_tempo.id, force_send=True) + template2 = pengajuan_tempo.env.ref('indoteknik_custom.mail_template_res_user_company_new_tempo_to_sales') + template2.send_mail(pengajuan_tempo.id, force_send=True) + return self.response({ + 'id': pengajuan_tempo.id, + 'user_id': user_id, + }) + 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_api/controllers/api_v1/state.py b/indoteknik_api/controllers/api_v1/state.py index 598ef70b..958359a7 100644 --- a/indoteknik_api/controllers/api_v1/state.py +++ b/indoteknik_api/controllers/api_v1/state.py @@ -8,7 +8,11 @@ class District(controller.Controller): @http.route(prefix + 'state', auth='public', methods=['GET', 'OPTIONS']) @controller.Controller.must_authorized() def get_state(self, **kw): + tempo = kw.get('tempo') parameters = [] + if tempo == 'true': + parameters.append(('country_id', '=', 100)) + name = kw.get('name') if name: @@ -18,7 +22,7 @@ class District(controller.Controller): states = request.env['res.country.state'].search(parameters) data = [] for state in states: - data.append({ 'id': state.id, 'name': state.name }) + data.append({ 'id': state.id, 'name': state.name}) return self.response(data) diff --git a/indoteknik_api/controllers/api_v1/user.py b/indoteknik_api/controllers/api_v1/user.py index 3be874fa..addf2c9f 100644 --- a/indoteknik_api/controllers/api_v1/user.py +++ b/indoteknik_api/controllers/api_v1/user.py @@ -403,6 +403,20 @@ class User(controller.Controller): 'user': self.response_with_token(user) }) + @http.route(prefix + 'user/<id>/after_request_tempo', auth='public', methods=['PUT', 'OPTIONS'], csrf=False) + @controller.Controller.must_authorized() + def update_user_tempo_after_request(self, **kw): + id = kw.get('id') + + user = request.env['res.users'].search([('id', '=', id)], limit=1) + if not user: + return self.response(code=404, description='User not found') + + + return self.response({ + 'user': self.response_with_token(user) + }) + @http.route(prefix + 'user/<id>/address', auth='public', methods=['GET', 'OPTIONS']) @controller.Controller.must_authorized() def get_user_address_by_id(self, **kw): diff --git a/indoteknik_api/models/__init__.py b/indoteknik_api/models/__init__.py index 892d2657..8c85938c 100644 --- a/indoteknik_api/models/__init__.py +++ b/indoteknik_api/models/__init__.py @@ -9,3 +9,4 @@ from . import sale_order from . import x_manufactures from . import website_content from . import coupon_program +from . import res_partner diff --git a/indoteknik_api/models/account_move.py b/indoteknik_api/models/account_move.py index 23a7076c..645c157a 100644 --- a/indoteknik_api/models/account_move.py +++ b/indoteknik_api/models/account_move.py @@ -7,6 +7,7 @@ class AccountMove(models.Model): def api_v1_single_response(self, account_move, context=False): sale_order = self.env['sale.order'].search([('name', '=', account_move.invoice_origin), ('state', '=', 'done')], limit=1) + sale_order_v2 = self.env['sale.order'].search([('name', '=', account_move.invoice_origin)],limit=1) amount_residual = account_move.amount_residual if sale_order.payment_status == 'settlement' or sale_order.payment_status == 'capture': amount_residual = 0 @@ -21,6 +22,9 @@ class AccountMove(models.Model): 'amount_residual': amount_residual, 'invoice_date': account_move.invoice_date.strftime('%d/%m/%Y') or '', 'efaktur': True if account_move.efaktur_document else False, + 'invoice_date_due': account_move.invoice_date_due.strftime('%d/%m/%Y') or '-', + 'sales_order': account_move.invoice_origin, + 'sales_order_id': sale_order_v2.id, } if isinstance(object, datetime.date): data['invoice_date'] = account_move.invoice_date.strftime('%d/%m/%Y') @@ -35,7 +39,6 @@ class AccountMove(models.Model): 'sales': account_move.invoice_user_id.name, 'amount_total': account_move.amount_total, 'amount_residual': amount_residual, - 'invoice_date_due': account_move.invoice_date_due.strftime('%d/%m/%Y') or '', 'customer': res_users.api_address_response(account_move.partner_id), 'products': [], } diff --git a/indoteknik_api/models/product_product.py b/indoteknik_api/models/product_product.py index f8869c7d..10922186 100644 --- a/indoteknik_api/models/product_product.py +++ b/indoteknik_api/models/product_product.py @@ -139,39 +139,39 @@ class ProductProduct(models.Model): return retValue def _get_website_price_exclude_tax(self): - default_divide_tax = float(1.11) + default_divide_tax = float(1.12) price_incl = self._get_website_price_include_tax() res = price_incl / default_divide_tax return math.floor(res) def _v2_get_website_price_exclude_tax(self): - default_divide_tax = float(1.11) + default_divide_tax = float(1.12) price_incl = self._v2_get_website_price_include_tax() res = price_incl / default_divide_tax return math.floor(res) def _get_website_price_after_disc_and_tax(self): - default_divide_tax = float(1.11) + default_divide_tax = float(1.12) price_after_disc = self._get_website_price_after_disc() res = price_after_disc / default_divide_tax res = math.ceil(res) return res def _v2_get_website_price_after_disc_and_tax(self): - default_divide_tax = float(1.11) + default_divide_tax = float(1.12) price_after_disc = self._v2_get_website_price_after_disc() res = price_after_disc / default_divide_tax res = math.ceil(res) return res def _get_website_tax(self): - default_percent_tax = float(11) + default_percent_tax = float(12) price_after_disc = self._get_website_price_after_disc_and_tax() res = price_after_disc * default_percent_tax / 100 return math.floor(res) def _v2_get_website_tax(self): - default_percent_tax = float(11) + default_percent_tax = float(12) price_after_disc = self._v2_get_website_price_after_disc_and_tax() res = price_after_disc * default_percent_tax / 100 return math.floor(res) diff --git a/indoteknik_api/models/res_partner.py b/indoteknik_api/models/res_partner.py new file mode 100644 index 00000000..0e09fbc6 --- /dev/null +++ b/indoteknik_api/models/res_partner.py @@ -0,0 +1,170 @@ +from odoo import models +import json +import base64 + +class ResPartner(models.Model): + _inherit = 'res.partner' + + def api_single_response(self, pengajuan_tempo, with_detail=''): + config = self.env['ir.config_parameter'] + + partner = pengajuan_tempo.partner_id + + dokumen_kirim = [ + ['Surat Tanda Terima Barang (STTB)', '0'], + ['Good Receipt (GR)', '1'], + ['Surat Terima Barang (STB)', '2'], + ['Lembar Penerimaan Barang (LPB)', '3'] + ] + dokumen_pengiriman = [] + if pengajuan_tempo.dokumen_pengiriman : + pengajuan_tempo_dokumen_pengiriman = pengajuan_tempo.dokumen_pengiriman + mapping_dokumen = {item[0]: item[1] for item in dokumen_kirim} + dokumen_pengiriman_list = [dokumen.strip() for dokumen in pengajuan_tempo_dokumen_pengiriman.split(',')] + dokumen_pengiriman = [mapping_dokumen.get(dokumen, '4') for dokumen in dokumen_pengiriman_list] + data = { + 'name' : pengajuan_tempo.name_tempo.name, + 'industry_id' : pengajuan_tempo.industry_id_tempo.id, + 'street' : pengajuan_tempo.street_tempo, + 'state' : pengajuan_tempo.state_id_tempo.id, + 'city' : pengajuan_tempo.city_id_tempo.id, + 'district' : pengajuan_tempo.district_id_tempo.id, + 'subDistrict' : pengajuan_tempo.subDistrict_id_tempo.id, + 'zip' : pengajuan_tempo.zip_tempo, + 'mobile' : pengajuan_tempo.mobile_tempo, + 'bank_name' : pengajuan_tempo.bank_name_tempo, + 'account_name' : pengajuan_tempo.account_name_tempo, + 'account_number' : pengajuan_tempo.account_number_tempo, + 'website' : pengajuan_tempo.website_tempo if pengajuan_tempo.website_tempo else '', + 'estimasi' : pengajuan_tempo.estimasi_tempo, + 'bersedia' : pengajuan_tempo.bersedia, + 'portal' : 'ada' if pengajuan_tempo.portal else 'tidak', + 'tempo_duration' : pengajuan_tempo.tempo_duration.id, + 'tempo_limit' : pengajuan_tempo.tempo_limit, + 'category_produk': ','.join([str(cat.id) for cat in pengajuan_tempo.category_produk_ids]) if pengajuan_tempo.category_produk_ids else '', + + # Kontak Perusahaan + 'direktur_tittle': pengajuan_tempo.direktur_tittle if pengajuan_tempo.direktur_tittle else '', + 'direktur_name' : pengajuan_tempo.direktur_name if pengajuan_tempo.direktur_name else '', + 'direktur_mobile' : pengajuan_tempo.direktur_mobile if pengajuan_tempo.direktur_mobile else '', + 'direktur_email' : pengajuan_tempo.direktur_email if pengajuan_tempo.direktur_email else '', + 'purchasing_tittle': pengajuan_tempo.purchasing_tittle if pengajuan_tempo.purchasing_tittle else '', + 'purchasing_name' : pengajuan_tempo.purchasing_name if pengajuan_tempo.purchasing_name else '', + 'purchasing_mobile' : pengajuan_tempo.purchasing_mobile if pengajuan_tempo.purchasing_mobile else '', + 'purchasing_email' : pengajuan_tempo.purchasing_email if pengajuan_tempo.purchasing_email else '', + 'finance_tittle': pengajuan_tempo.finance_tittle if pengajuan_tempo.finance_tittle else '', + 'finance_name' : pengajuan_tempo.finance_name if pengajuan_tempo.finance_name else '', + 'finance_mobile' : pengajuan_tempo.finance_mobile if pengajuan_tempo.finance_mobile else '', + 'finance_email' : pengajuan_tempo.finance_email if pengajuan_tempo.finance_email else '', + + # Pengiriman + 'PIC_tittle' : pengajuan_tempo.pic_tittle if pengajuan_tempo.pic_tittle else '', + 'PIC_name' : pengajuan_tempo.pic_name if pengajuan_tempo.pic_name else '', + 'street_pengiriman' : pengajuan_tempo.street_pengiriman if pengajuan_tempo.street_pengiriman else '', + 'state_pengiriman' : pengajuan_tempo.state_id_pengiriman.id if pengajuan_tempo.state_id_pengiriman else '', + 'city_pengiriman' : pengajuan_tempo.city_id_pengiriman.id if pengajuan_tempo.city_id_pengiriman else '', + 'district_pengiriman': pengajuan_tempo.district_id_pengiriman.id if pengajuan_tempo.district_id_pengiriman else '', + 'subDistrict_pengiriman': pengajuan_tempo.subDistrict_id_pengiriman.id if pengajuan_tempo.subDistrict_id_pengiriman else '', + 'zip_pengiriman' : pengajuan_tempo.zip_pengiriman if pengajuan_tempo.zip_pengiriman else '', + 'invoice_pic_tittle' : pengajuan_tempo.invoice_pic_tittle if pengajuan_tempo.invoice_pic_tittle else '', + 'invoice_pic' : pengajuan_tempo.invoice_pic if pengajuan_tempo.invoice_pic else '', + 'street_invoice' : pengajuan_tempo.street_invoice if pengajuan_tempo.street_invoice else '', + 'state_invoice' : pengajuan_tempo.state_id_invoice.id if pengajuan_tempo.state_id_invoice else '', + 'city_invoice' : pengajuan_tempo.city_id_invoice.id if pengajuan_tempo.city_id_invoice else '', + 'district_invoice': pengajuan_tempo.district_id_invoice.id if pengajuan_tempo.district_id_invoice else '', + 'subDistrict_invoice': pengajuan_tempo.subDistrict_id_invoice.id if pengajuan_tempo.subDistrict_id_invoice else '', + 'zip_invoice': pengajuan_tempo.zip_invoice if pengajuan_tempo.zip_invoice else '', + 'tukar_invoice_input' : pengajuan_tempo.tukar_invoice if pengajuan_tempo.tukar_invoice else '', + 'tukar_invoice_input_pembayaran' : pengajuan_tempo.jadwal_bayar if pengajuan_tempo.jadwal_bayar else '', + 'dokumen_pengiriman' : ','.join(dokumen_pengiriman) if dokumen_pengiriman else '', + 'dokumen_pengiriman_input' : pengajuan_tempo.dokumen_pengiriman_input if pengajuan_tempo.dokumen_pengiriman_input else '', + 'dokumen_kirim_input' : pengajuan_tempo.dokumen_kirim_input if pengajuan_tempo.dokumen_kirim_input else '', + 'dokumen_pengiriman_invoice' : pengajuan_tempo.dokumen_invoice if pengajuan_tempo.dokumen_invoice else '', + 'is_same_addrees': pengajuan_tempo.is_same_address if pengajuan_tempo.is_same_address else False, + 'is_same_addrees_street': pengajuan_tempo.is_same_address_street if pengajuan_tempo.is_same_address_street else False, + 'supplier_ids': [ + { + 'id': supplier.id, + 'supplier': supplier.name_supplier, + 'telepon': supplier.phone, + 'pic': supplier.pic_name, + 'credit_limit': supplier.credit_limit, + 'durasi_tempo': supplier.tempo_duration + } + for supplier in pengajuan_tempo.supplier_ids + ] if pengajuan_tempo.supplier_ids else '', + # Dokumen + 'dokumen_npwp': + { + 'name': pengajuan_tempo.dokumen_npwp.name, + 'base64': pengajuan_tempo.dokumen_npwp.datas.decode('utf-8'), + 'format': pengajuan_tempo.dokumen_npwp.mimetype, + } if pengajuan_tempo.dokumen_npwp else '', + 'dokumen_sppkp': { + 'name': pengajuan_tempo.dokumen_sppkp.name, + 'base64': pengajuan_tempo.dokumen_sppkp.datas.decode('utf-8'), + 'format': pengajuan_tempo.dokumen_sppkp.mimetype, + } if pengajuan_tempo.dokumen_sppkp else '', + 'dokumen_nib': + { + 'name': pengajuan_tempo.dokumen_nib.name, + 'base64': pengajuan_tempo.dokumen_nib.datas.decode('utf-8'), + 'format': pengajuan_tempo.dokumen_nib.mimetype, + }if pengajuan_tempo.dokumen_nib else '', + 'dokumen_siup': + { + 'name': pengajuan_tempo.dokumen_siup.name, + 'base64': pengajuan_tempo.dokumen_siup.datas.decode('utf-8'), + 'format': pengajuan_tempo.dokumen_siup.mimetype, + }if pengajuan_tempo.dokumen_siup else '', + 'dokumen_tdp': + { + 'name': pengajuan_tempo.dokumen_tdp.name, + 'base64': pengajuan_tempo.dokumen_tdp.datas.decode('utf-8'), + 'format': pengajuan_tempo.dokumen_tdp.mimetype, + }if pengajuan_tempo.dokumen_tdp else '', + 'dokumen_skdp': + { + 'name': pengajuan_tempo.dokumen_skdp.name, + 'base64': pengajuan_tempo.dokumen_skdp.datas.decode('utf-8'), + 'format': pengajuan_tempo.dokumen_skdp.mimetype, + }if pengajuan_tempo.dokumen_skdp else '', + 'dokumen_skt': + { + 'name': pengajuan_tempo.dokumen_skt.name, + 'base64': pengajuan_tempo.dokumen_skt.datas.decode('utf-8'), + 'format': pengajuan_tempo.dokumen_skt.mimetype, + }if pengajuan_tempo.dokumen_skt else '', + 'dokumen_akta_perubahan': { + 'name': pengajuan_tempo.dokumen_akta_perubahan.name, + 'base64': pengajuan_tempo.dokumen_akta_perubahan.datas.decode('utf-8'), + 'format': pengajuan_tempo.dokumen_akta_perubahan.mimetype, + } if pengajuan_tempo.dokumen_akta_perubahan else '', + 'dokumen_ktp_dirut': { + 'name': pengajuan_tempo.dokumen_ktp_dirut.name, + 'base64': pengajuan_tempo.dokumen_ktp_dirut.datas.decode('utf-8'), + 'format': pengajuan_tempo.dokumen_ktp_dirut.mimetype, + } if pengajuan_tempo.dokumen_ktp_dirut else '', + 'dokumen_akta_pendirian': { + 'name': pengajuan_tempo.dokumen_akta_pendirian.name, + 'base64': pengajuan_tempo.dokumen_akta_pendirian.datas.decode('utf-8'), + 'format': pengajuan_tempo.dokumen_akta_pendirian.mimetype, + } if pengajuan_tempo.dokumen_akta_pendirian else '', + 'dokumen_laporan_keuangan': { + 'name': pengajuan_tempo.dokumen_laporan_keuangan.name, + 'base64': pengajuan_tempo.dokumen_laporan_keuangan.datas.decode('utf-8'), + 'format': pengajuan_tempo.dokumen_laporan_keuangan.mimetype, + } if pengajuan_tempo.dokumen_laporan_keuangan else '', + 'dokumen_foto_kantor': { + 'name': pengajuan_tempo.dokumen_foto_kantor.name, + 'base64': pengajuan_tempo.dokumen_foto_kantor.datas.decode('utf-8'), + 'format': pengajuan_tempo.dokumen_foto_kantor.mimetype, + } if pengajuan_tempo.dokumen_foto_kantor else '', + 'dokumen_tempat_bekerja': { + 'name': pengajuan_tempo.dokumen_tempat_bekerja.name, + 'base64': pengajuan_tempo.dokumen_tempat_bekerja.datas.decode('utf-8'), + 'format': pengajuan_tempo.dokumen_tempat_bekerja.mimetype, + } if pengajuan_tempo.dokumen_tempat_bekerja else '', + } + + return data
\ No newline at end of file diff --git a/indoteknik_api/models/res_users.py b/indoteknik_api/models/res_users.py index 77aeeef7..2021b0bb 100644 --- a/indoteknik_api/models/res_users.py +++ b/indoteknik_api/models/res_users.py @@ -1,5 +1,5 @@ from odoo import models - +from odoo.http import request class ResUsers(models.Model): _inherit = 'res.users' @@ -15,8 +15,14 @@ class ResUsers(models.Model): 'director': 3 } partner_tempo = False + is_tempo_request = request.env['user.pengajuan.tempo.request'].search([('user_company_id', '=', main_partner.id)], limit=1) + tempo_progres = ( + 'review' if is_tempo_request.state_tempo in ('draft', 'approval_sales', 'approval_finance') else + 'rejected' if is_tempo_request.state_tempo == 'reject' else + 'approve' if is_tempo_request.state_tempo == 'approval_director' else '' + ) if main_partner: - partner_tempo = main_partner.get_check_tempo_partner() + partner_tempo = True if 'tempo' in main_partner.get_check_payment_term().lower() else False data = { 'id': res_user.id, @@ -36,7 +42,8 @@ class ResUsers(models.Model): 'so_approval': main_partner.use_so_approval, 'only_ready_stock': main_partner.use_only_ready_stock }, - 'partner_tempo': partner_tempo + 'partner_tempo': partner_tempo, + 'tempo_progres': tempo_progres } return data diff --git a/indoteknik_custom/__manifest__.py b/indoteknik_custom/__manifest__.py index 5f77d2de..c1593c9e 100755 --- a/indoteknik_custom/__manifest__.py +++ b/indoteknik_custom/__manifest__.py @@ -8,7 +8,7 @@ 'author': 'Rafi Zadanly', 'website': '', 'images': ['assets/favicon.ico'], - 'depends': ['base', 'coupon', 'delivery', 'sale', 'sale_management', 'vit_kelurahan'], + 'depends': ['base', 'coupon', 'delivery', 'sale', 'sale_management', 'vit_kelurahan', 'vit_efaktur' ], 'data': [ 'security/ir.model.access.csv', 'views/group_partner.xml', @@ -30,6 +30,7 @@ 'views/web_logging/user_activity_log.xml', 'views/web_logging/web_utm_source.xml', 'views/user_company_request.xml', + 'views/user_pengajuan_tempo_request.xml', 'views/vit_kelurahan.xml', 'views/vit_kecamatan.xml', 'views/vit_kota.xml', @@ -148,6 +149,7 @@ 'views/approval_retur_picking.xml', 'views/form_vendor_approval_multi_approve.xml', 'views/form_vendor_approval_multi_reject.xml', + 'views/user_pengajuan_tempo.xml', 'report/report.xml', 'report/report_banner_banner.xml', 'report/report_banner_banner2.xml', @@ -156,6 +158,7 @@ 'report/report_picking.xml', 'report/report_sale_order.xml', 'views/vendor_sla.xml', + 'views/coretax_faktur.xml', ], 'demo': [], 'css': [], diff --git a/indoteknik_custom/models/__init__.py b/indoteknik_custom/models/__init__.py index 70a84bd0..43fbf146 100755 --- a/indoteknik_custom/models/__init__.py +++ b/indoteknik_custom/models/__init__.py @@ -34,6 +34,7 @@ from . import stock_picking_type from . import stock_picking from . import stock_vendor from . import user_company_request +from . import user_pengajuan_tempo_request from . import users from . import website_brand_homepage from . import website_categories_homepage @@ -131,7 +132,11 @@ from . import approval_unreserve from . import vendor_approval from . import partner from . import find_page +from . import user_pengajuan_tempo_line +from . import user_pengajuan_tempo from . import approval_retur_picking from . import va_multi_approve from . import va_multi_reject from . import vendor_sla +from . import stock_immediate_transfer +from . import coretax_fatur diff --git a/indoteknik_custom/models/account_move.py b/indoteknik_custom/models/account_move.py index 725b3c2d..42678847 100644 --- a/indoteknik_custom/models/account_move.py +++ b/indoteknik_custom/models/account_move.py @@ -325,3 +325,35 @@ class AccountMove(models.Model): # if rec.statement_line_id and not rec.statement_line_id.statement_id.is_edit and rec.statement_line_id.statement_id.state == 'confirm': # raise UserError('Bank Statement di Lock, Minta admin reconcile untuk unlock') # return res + + def validate_faktur_for_export(self): + invoices = self.filtered(lambda inv: not inv.is_efaktur_exported and + inv.state == 'posted' and + inv.move_type == 'out_invoice') + + invalid_invoices = self - invoices + if invalid_invoices: + invalid_ids = ", ".join(str(inv.id) for inv in invalid_invoices) + raise UserError(_( + "Faktur dengan ID berikut tidak valid untuk diekspor: {}.\n" + "Pastikan faktur dalam status 'posted', belum diekspor, dan merupakan 'out_invoice'.".format(invalid_ids) + )) + + return invoices + + def export_faktur_to_xml(self): + + valid_invoices = self.validate_faktur_for_export() + + # Panggil model coretax.faktur untuk menghasilkan XML + coretax_faktur = self.env['coretax.faktur'].create({}) + response = coretax_faktur.export_to_download(invoices=valid_invoices) + + current_time = datetime.utcnow() + # Tandai faktur sebagai sudah diekspor + valid_invoices.write({ + 'is_efaktur_exported': True, + 'date_efaktur_exported': current_time, # Set tanggal ekspor + }) + + return response diff --git a/indoteknik_custom/models/coretax_fatur.py b/indoteknik_custom/models/coretax_fatur.py new file mode 100644 index 00000000..ff8606b1 --- /dev/null +++ b/indoteknik_custom/models/coretax_fatur.py @@ -0,0 +1,119 @@ +from odoo import models, fields +import xml.etree.ElementTree as ET +from xml.dom import minidom +import base64 +import re + +class CoretaxFaktur(models.Model): + _name = 'coretax.faktur' + _description = 'Export Faktur ke XML' + + export_file = fields.Binary(string="Export File", ) + export_filename = fields.Char(string="Export File", ) + + def validate_and_format_number(slef, input_number): + # Hapus semua karakter non-digit + cleaned_number = re.sub(r'\D', '', input_number) + + total_sum = sum(int(char) for char in cleaned_number) + if total_sum == 0 : + return '0000000000000000' + + # Hitung jumlah digit + digit_count = len(cleaned_number) + + # Jika jumlah digit kurang dari 15, tambahkan nol di depan + if digit_count < 16: + cleaned_number = cleaned_number.zfill(16) + + return cleaned_number + + def generate_xml(self, invoices=None): + # Buat root XML + root = ET.Element('TaxInvoiceBulk', { + 'xmlns:xsi': "http://www.w3.org/2001/XMLSchema-instance", + 'xsi:noNamespaceSchemaLocation': "TaxInvoice.xsd" + }) + ET.SubElement(root, 'TIN').text = '0742260227086000' + + # Tambahkan elemen ListOfTaxInvoice + list_of_tax_invoice = ET.SubElement(root, 'ListOfTaxInvoice') + + # Dapatkan data faktur + # inv_obj = self.env['account.move'] + # invoices = inv_obj.search([('is_efaktur_exported','=',True), + # ('state','=','posted'), + # ('efaktur_id','!=', False), + # ('move_type','=','out_invoice')], limit = 5) + + for invoice in invoices: + tax_invoice = ET.SubElement(list_of_tax_invoice, 'TaxInvoice') + buyerTIN = self.validate_and_format_number(invoice.partner_id.npwp) + buyerIDTKU = buyerTIN.ljust(len(buyerTIN) + 6, '0') if sum(int(char) for char in buyerTIN) > 0 else '000000' + + # Tambahkan elemen faktur + ET.SubElement(tax_invoice, 'TaxInvoiceDate').text = invoice.invoice_date.strftime('%Y-%m-%d') if invoice.invoice_date else '' + ET.SubElement(tax_invoice, 'TaxInvoiceOpt').text = 'Normal' + ET.SubElement(tax_invoice, 'TrxCode').text = '04' + ET.SubElement(tax_invoice, 'AddInfo') + ET.SubElement(tax_invoice, 'CustomDoc') + ET.SubElement(tax_invoice, 'RefDesc').text = invoice.name + ET.SubElement(tax_invoice, 'FacilityStamp') + ET.SubElement(tax_invoice, 'SellerIDTKU').text = '0742260227086000000000' + ET.SubElement(tax_invoice, 'BuyerTin').text = buyerTIN + ET.SubElement(tax_invoice, 'BuyerDocument').text = 'TIN' if sum(int(char) for char in buyerTIN) > 0 else 'Other ID' + ET.SubElement(tax_invoice, 'BuyerCountry').text = 'IDN' + ET.SubElement(tax_invoice, 'BuyerDocumentNumber').text = str(invoice.partner_id.id) + ET.SubElement(tax_invoice, 'BuyerName').text = invoice.partner_id.nama_wajib_pajak or '' + ET.SubElement(tax_invoice, 'BuyerAdress').text = invoice.partner_id.alamat_lengkap_text or '' + ET.SubElement(tax_invoice, 'BuyerEmail').text = invoice.partner_id.email or '' + ET.SubElement(tax_invoice, 'BuyerIDTKU').text = buyerIDTKU + + # Tambahkan elemen ListOfGoodService + list_of_good_service = ET.SubElement(tax_invoice, 'ListOfGoodService') + for line in invoice.invoice_line_ids: + otherTaxBase = round(line.price_subtotal * (11/12)) if line.price_subtotal else 0 + good_service = ET.SubElement(list_of_good_service, 'GoodService') + ET.SubElement(good_service, 'Opt').text = 'A' + ET.SubElement(good_service, 'Code') + ET.SubElement(good_service, 'Name').text = line.name + ET.SubElement(good_service, 'Unit').text = 'UM.0018' + ET.SubElement(good_service, 'Price').text = str(round(line.price_subtotal/line.quantity, 2)) if line.price_subtotal else '0' + ET.SubElement(good_service, 'Qty').text = str(line.quantity) + ET.SubElement(good_service, 'TotalDiscount').text = '0' + ET.SubElement(good_service, 'TaxBase').text = str(round(line.price_subtotal)) if line.price_subtotal else '0' + ET.SubElement(good_service, 'OtherTaxBase').text = str(otherTaxBase) + ET.SubElement(good_service, 'VATRate').text = '12' + ET.SubElement(good_service, 'VAT').text = str(round(otherTaxBase * 0.12, 2)) + ET.SubElement(good_service, 'STLGRate').text = '0' + ET.SubElement(good_service, 'STLG').text = '0' + + # Pretty print XML + xml_str = ET.tostring(root, encoding='utf-8') + xml_pretty = minidom.parseString(xml_str).toprettyxml(indent=" ") + return xml_pretty + + def export_to_download(self, invoices): + # Generate XML content + xml_content = self.generate_xml(invoices) + + # Encode content to Base64 + xml_encoded = base64.b64encode(xml_content.encode('utf-8')) + + # Buat attachment untuk XML + attachment = self.env['ir.attachment'].create({ + 'name': 'Faktur_XML.xml', + 'type': 'binary', + 'datas': xml_encoded, + 'mimetype': 'application/xml', + 'store_fname': 'faktur_xml.xml', + }) + + # Kembalikan URL untuk download dengan header 'Content-Disposition' + response = { + 'type': 'ir.actions.act_url', + 'url': '/web/content/{}?download=true'.format(attachment.id), + 'target': 'self', + } + + return response diff --git a/indoteknik_custom/models/product_template.py b/indoteknik_custom/models/product_template.py index 6fb8c7a0..5bedae13 100755 --- a/indoteknik_custom/models/product_template.py +++ b/indoteknik_custom/models/product_template.py @@ -5,7 +5,9 @@ import logging import requests import json import re +import qrcode, base64 from bs4 import BeautifulSoup +from io import BytesIO _logger = logging.getLogger(__name__) @@ -58,10 +60,30 @@ class ProductTemplate(models.Model): ('sp', 'Spare Part'), ('acc', 'Accessories') ], string='Kind of', copy=False) - sni = fields.Boolean(string='SNI') + sni = fields.Boolean(string='SNI') tkdn = fields.Boolean(string='TKDN') short_spesification = fields.Char(string='Short Spesification') merchandise_ok = fields.Boolean(string='Product Promotion') + print_barcode = fields.Boolean(string='Print Barcode', default=True) + # qr_code = fields.Binary("QR Code", compute='_compute_qr_code') + + # def _compute_qr_code(self): + # for rec in self.product_variant_ids: + # qr = qrcode.QRCode( + # version=1, + # error_correction=qrcode.constants.ERROR_CORRECT_L, + # box_size=5, + # border=4, + # ) + # qr.add_data(rec.display_name) + # 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() + + # rec.qr_code = qr_code_img @api.constrains('name', 'internal_reference', 'x_manufacture') def required_public_categ_ids(self): @@ -379,6 +401,30 @@ class ProductProduct(models.Model): qty_rpo = fields.Float(string='Qty RPO', compute='_get_qty_rpo') plafon_qty = fields.Float(string='Max Plafon', compute='_get_plafon_qty_product') merchandise_ok = fields.Boolean(string='Product Promotion') + qr_code_variant = fields.Binary("QR Code Variant", compute='_compute_qr_code_variant') + + def _compute_qr_code_variant(self): + for rec in self: + # Skip inactive variants + if not rec.active: + rec.qr_code_variant = False # Clear the QR Code for archived variants + continue + + qr = qrcode.QRCode( + version=1, + error_correction=qrcode.constants.ERROR_CORRECT_L, + box_size=5, + border=4, + ) + qr.add_data(rec.default_code) + 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() + + rec.qr_code_variant = qr_code_img def _get_clean_website_description(self): for rec in self: diff --git a/indoteknik_custom/models/purchase_order.py b/indoteknik_custom/models/purchase_order.py index 9388ae4c..799c4db0 100755 --- a/indoteknik_custom/models/purchase_order.py +++ b/indoteknik_custom/models/purchase_order.py @@ -74,6 +74,29 @@ class PurchaseOrder(models.Model): approve_by = fields.Many2one('res.users', string='Approve By') exclude_incoming = fields.Boolean(string='Exclude Incoming', default=False, help='Centang jika tidak mau masuk perhitungan Incoming Qty') + not_update_purchasepricelist = fields.Boolean(string='Not Update Purchase Pricelist?') + # total_cost_service = fields.Float(string='Total Cost Service') + # total_delivery_amt = fields.Float(string='Total Delivery Amt') + + # @api.onchange('total_cost_service') + # def _onchange_total_cost_service(self): + # for order in self: + # lines = order.order_line + # if lines: + # # Hitung nilai rata-rata cost_service + # per_line_cost_service = order.total_cost_service / len(lines) + # for line in lines: + # line.cost_service = per_line_cost_service + + # @api.onchange('total_delivery_amt') + # def _onchange_total_delivery_amt(self): + # for order in self: + # lines = order.order_line + # if lines: + # # Hitung nilai rata-rata delivery_amt + # per_line_delivery_amt = order.total_delivery_amt / len(lines) + # for line in lines: + # line.delivery_amt = per_line_delivery_amt def _compute_total_margin_match(self): for purchase in self: @@ -114,6 +137,7 @@ class PurchaseOrder(models.Model): 'ref': self.name, 'invoice_date': current_date, 'date': current_date, + 'invoice_origin': self.name, 'move_type': 'in_invoice' } @@ -164,6 +188,11 @@ class PurchaseOrder(models.Model): self.bills_pelunasan_id = bills.id + lognote_message = ( + f"Vendor bill created from: {self.name} ({self.partner_ref})" + ) + bills.message_post(body=lognote_message) + return { 'name': _('Account Move'), 'view_mode': 'tree,form', @@ -173,12 +202,10 @@ class PurchaseOrder(models.Model): 'domain': [('id', '=', bills.id)] } - - def create_bill_dp(self): if not self.env.user.is_accounting: raise UserError('Hanya Accounting yang bisa bikin bill dp') - + current_date = datetime.utcnow() data_bills = { 'partner_id': self.partner_id.id, @@ -186,8 +213,8 @@ class PurchaseOrder(models.Model): 'ref': self.name, 'invoice_date': current_date, 'date': current_date, + 'invoice_origin': self.name, 'move_type': 'in_invoice' - } bills = self.env['account.move'].create([data_bills]) @@ -196,14 +223,13 @@ class PurchaseOrder(models.Model): data_line_bills = { 'move_id': bills.id, - 'product_id': product_dp.id, #product down payment - 'account_id': 401, #Uang Muka persediaan barang dagang + 'product_id': product_dp.id, # product down payment + 'account_id': 401, # Uang Muka persediaan barang dagang 'quantity': 1, 'product_uom_id': 1, 'tax_ids': [line[0].taxes_id.id for line in self.order_line], } - bills_line = self.env['account.move.line'].create([data_line_bills]) self.bills_dp_id = bills.id @@ -212,6 +238,11 @@ class PurchaseOrder(models.Model): move_line.name = '[IT.121456] Down Payment' move_line.partner_id = self.partner_id.id + lognote_message = ( + f"Vendor bill created from: {self.name} ({self.partner_ref})" + ) + bills.message_post(body=lognote_message) + return { 'name': _('Account Move'), 'view_mode': 'tree,form', @@ -620,7 +651,8 @@ class PurchaseOrder(models.Model): raise UserError("Tidak ada link dengan SO, harus approval Merchandise") send_email = False - self.add_product_to_pricelist() + if not self.not_update_purchasepricelist: + self.add_product_to_pricelist() for line in self.order_line: if not line.product_id.purchase_ok: raise UserError("Terdapat barang yang tidak bisa diproses") diff --git a/indoteknik_custom/models/requisition.py b/indoteknik_custom/models/requisition.py index 32a9f94f..c972b485 100644 --- a/indoteknik_custom/models/requisition.py +++ b/indoteknik_custom/models/requisition.py @@ -82,11 +82,11 @@ class Requisition(models.Model): state = ['done', 'sale'] if self.sale_order_id.state in state: raise UserError('SO sudah Confirm, akan berakibat double Purchase melalui PJ') - if self.env.user.id not in [377, 19]: + if self.env.user.id not in [377, 19, 28]: raise UserError('Hanya Vita dan Darren Yang Bisa Approve') - if self.env.user.id == 377: + if self.env.user.id == 377 or self.env.user.id == 28: self.sales_approve = True - elif self.env.user.id == 19: + elif self.env.user.id == 19 or self.env.user.id == 28: if not self.sales_approve: raise UserError('Vita Belum Approve') self.merchandise_approve = True diff --git a/indoteknik_custom/models/res_partner.py b/indoteknik_custom/models/res_partner.py index da4a6cb6..57fab403 100644 --- a/indoteknik_custom/models/res_partner.py +++ b/indoteknik_custom/models/res_partner.py @@ -20,6 +20,78 @@ class ResPartner(models.Model): domain="[('internal_type', '=', 'receivable'), ('deprecated', '=', False), ('company_id', '=', current_company_id)]", help="This account will be used instead of the default one as the receivable account for the current partner", default=395) + # Referensi + supplier_ids = fields.Many2many('user.pengajuan.tempo.line', string="Suppliers") + + # informasi perusahaan + name_tempo = fields.Many2one('res.partner', string='Nama Perusahaan',tracking=True) + industry_id_tempo = fields.Many2one('res.partner.industry', 'Customer Industry', readonly=True) + street_tempo = fields.Char(string="Alamat Perusahaan") + state_id_tempo = fields.Many2one('res.country.state', string='State') + city_id_tempo = fields.Many2one('vit.kota', string='City') + zip_tempo = fields.Char(string="Zip") + mobile_tempo = fields.Char(string="No. Telfon Perusahaan") + bank_name_tempo = fields.Char(string="Nama Bank") + account_name_tempo = fields.Char(string="Nama Rekening") + account_number_tempo = fields.Char(string="Nomor Rekening Bank") + website_tempo = fields.Char(string='Website') + portal = fields.Boolean(string='Portal Website') + estimasi_tempo = fields.Char(string='Estimasi Pembelian Pertahun') + tempo_duration = fields.Many2one('account.payment.term', string='Durasi Tempo') + tempo_limit = fields.Char(string='Limit Tempo') + category_produk_ids = fields.Many2many('product.public.category', string='Kategori Produk yang Digunakan', domain=lambda self: self._get_default_category_domain()) + + @api.model + def _get_default_category_domain(self): + return [('parent_id', '=', False)] + + # Kontak Perusahaan + direktur_name = fields.Char(string='Nama Lengkap Direktur') + direktur_mobile = fields.Char(string='No. Telpon Direktur') + direktur_email = fields.Char(string='Email Direktur') + purchasing_name = fields.Char(string='Nama Purchasing') + purchasing_mobile = fields.Char(string='No. Telpon Purchasing') + purchasing_email = fields.Char(string='Email Purchasing') + finance_name = fields.Char(string='Nama Finance') + finance_mobile = fields.Char(string='No. Telpon Finance') + finance_email = fields.Char(string='Email Finance') + + # Pengiriman + pic_name = fields.Char(string='Nama PIC Penerimaan Barang') + street_pengiriman = fields.Char(string="Alamat Perusahaan") + state_id_pengiriman = fields.Many2one('res.country.state', string='State') + city_id_pengiriman = fields.Many2one('vit.kota', string='City') + district_id_pengiriman = fields.Many2one('vit.kecamatan', string='Kecamatan') + subDistrict_id_pengiriman = fields.Many2one('vit.kelurahan', string='Kelurahan') + zip_pengiriman = fields.Char(string="Zip") + invoice_pic = fields.Char(string='Nama PIC Penerimaan Invoice') + street_invoice = fields.Char(string="Alamat Perusahaan") + state_id_invoice = fields.Many2one('res.country.state', string='State') + city_id_invoice = fields.Many2one('vit.kota', string='City') + district_id_invoice = fields.Many2one('vit.kecamatan', string='Kecamatan') + subDistrict_id_invoice = fields.Many2one('vit.kelurahan', string='Kelurahan') + zip_invoice = fields.Char(string="Zip") + tukar_invoice = fields.Char(string='Jadwal Penukaran Invoice') + jadwal_bayar = fields.Char(string='Jadwal Pembayaran') + dokumen_pengiriman = fields.Char(string='Dokumen Tanda Terima yang Diberikan Pada Saat Pengiriman Barang') + dokumen_pengiriman_input = fields.Char(string='Dokumen yang Dibawa Saat Pengiriman Barang') + dokumen_invoice = fields.Char(string='Dokumen yang dilampirkan saat Pengiriman Invoice') + + # Dokumen + dokumen_npwp = fields.Many2one('ir.attachment', string="NPWP Perusahaan", tracking=3, readonly=True) + dokumen_sppkp = fields.Many2one('ir.attachment', string="SPPKP Perusahaan", tracking=3, readonly=True) + dokumen_nib = fields.Many2one('ir.attachment', string="NIB (SIUP/TDP/SKDP)", tracking=3, readonly=True,) + dokumen_siup = fields.Many2one('ir.attachment', string="SIUP Perusahaan", tracking=3, readonly=True) + dokumen_tdp = fields.Many2one('ir.attachment', string="TDP Perusahaan", tracking=3, readonly=True) + dokumen_skdp = fields.Many2one('ir.attachment', string="SKDP Perusahaan",tracking=True, readonly=True) + dokumen_skt = fields.Many2one('ir.attachment', string="SKT Perusahaan", tracking=True, readonly=True) + dokumen_akta_perubahan = fields.Many2one('ir.attachment', string="Akta Perubahan", tracking=3, readonly=True) + dokumen_ktp_dirut = fields.Many2one('ir.attachment', string="KTP Dirut/Direktur", tracking=3, readonly=True) + dokumen_akta_pendirian = fields.Many2one('ir.attachment', string="Akta Pendirian", tracking=3, readonly=True) + dokumen_laporan_keuangan = fields.Many2one('ir.attachment', string="Laporan Keuangan", tracking=3, readonly=True) + dokumen_foto_kantor = fields.Many2one('ir.attachment', string=" Foto Kantor (Tampak Depan)", tracking=3, readonly=True) + dokumen_tempat_bekerja = fields.Many2one('ir.attachment', string="Tempat Bekerja", tracking=3, readonly=True) + reference_number = fields.Char(string="Reference Number") company_type_id = fields.Many2one('res.partner.company_type', string='Company Type') custom_pricelist_id = fields.Many2one('product.pricelist', string='Price Matrix') @@ -92,23 +164,22 @@ class ResPartner(models.Model): if partner.company_type == 'person' and not partner.parent_id: partner.alamat_lengkap_text = partner.street # if partner.company_type == 'person' and partner.parent_id: - # partner.alamat_lengkap_text = partner.parent_id.alamat_lengkap_text + # partner.alamat_lengkap_text = partner.parent_id.alamat_lengkap_text - - alamat_lengkap_text = fields.Text(string="Alamat Lengkap", required=False , tracking=3) + alamat_lengkap_text = fields.Text(string="Alamat Lengkap", required=False, tracking=3) def write(self, vals): res = super(ResPartner, self).write(vals) - # - # # if 'property_payment_term_id' in vals: - # # if not self.env.user.is_accounting and vals['property_payment_term_id'] != 26: - # # raise UserError('Hanya Finance Accounting yang dapat merubah payment term') - # - # # group_id = self.env.ref('indoteknik_custom.group_role_merchandiser').id - # # users_in_group = self.env['res.users'].search([('groups_id', 'in', [group_id])]) - # # if self.env.user.id not in users_in_group.mapped('id'): - # # raise UserError('You name it') - # + # + # # if 'property_payment_term_id' in vals: + # # if not self.env.user.is_accounting and vals['property_payment_term_id'] != 26: + # # raise UserError('Hanya Finance Accounting yang dapat merubah payment term') + # + # # group_id = self.env.ref('indoteknik_custom.group_role_merchandiser').id + # # users_in_group = self.env['res.users'].search([('groups_id', 'in', [group_id])]) + # # if self.env.user.id not in users_in_group.mapped('id'): + # # raise UserError('You name it') + # return res def write(self, vals): @@ -133,8 +204,74 @@ class ResPartner(models.Model): vals['sppkp'] = vals.get('sppkp', self.sppkp) vals['alamat_lengkap_text'] = vals.get('alamat_lengkap_text', self.alamat_lengkap_text) vals['industry_id'] = vals.get('industry_id', self.industry_id.id if self.industry_id else None) - vals['company_type_id'] = vals.get('company_type_id', - self.company_type_id.id if self.company_type_id else None) + vals['company_type_id'] = vals.get('company_type_id', self.company_type_id.id if self.company_type_id else None) + + # Referensi + vals['supplier_ids'] = vals.get('supplier_ids', self.supplier_ids) + + # informasi perusahaan + vals['name_tempo'] = vals.get('name_tempo', self.name_tempo) + vals['industry_id_tempo'] = vals.get('industry_id_tempo', self.industry_id_tempo) + vals['street_tempo'] = vals.get('street_tempo', self.street_tempo) + vals['state_id_tempo'] = vals.get('state_id_tempo', self.state_id_tempo) + vals['city_id_tempo'] = vals.get('city_id_tempo', self.city_id_tempo) + vals['zip_tempo'] = vals.get('zip_tempo', self.zip_tempo) + vals['bank_name_tempo'] = vals.get('bank_name_tempo', self.bank_name_tempo) + vals['account_name_tempo'] = vals.get('account_name_tempo', self.account_name_tempo) + vals['account_number_tempo'] = vals.get('account_number_tempo', self.account_number_tempo) + vals['website_tempo'] = vals.get('website_tempo', self.website_tempo) + vals['portal'] = vals.get('portal', self.portal) + vals['estimasi_tempo'] = vals.get('estimasi_tempo', self.estimasi_tempo) + vals['tempo_duration'] = vals.get('tempo_duration', self.tempo_duration) + vals['tempo_limit'] = vals.get('tempo_limit', self.tempo_limit) + vals['category_produk_ids'] = vals.get('category_produk_ids', self.category_produk_ids) + + # Kontak Perusahaan + vals['direktur_name'] = vals.get('direktur_name', self.direktur_name) + vals['direktur_mobile'] = vals.get('direktur_mobile', self.direktur_mobile) + vals['direktur_email'] = vals.get('direktur_email', self.direktur_email) + vals['purchasing_name'] = vals.get('purchasing_name', self.purchasing_name) + vals['purchasing_mobile'] = vals.get('purchasing_mobile', self.purchasing_mobile) + vals['purchasing_email'] = vals.get('purchasing_email', self.purchasing_email) + vals['finance_name'] = vals.get('finance_name', self.finance_name) + vals['finance_mobile'] = vals.get('finance_mobile', self.finance_mobile) + vals['finance_email'] = vals.get('finance_email', self.finance_email) + + # Pengiriman + vals['pic_name'] = vals.get('pic_name', self.pic_name) + vals['street_pengiriman'] = vals.get('street_pengiriman', self.street_pengiriman) + vals['state_id_pengiriman'] = vals.get('state_id_pengiriman', self.state_id_pengiriman) + vals['city_id_pengiriman'] = vals.get('city_id_pengiriman', self.city_id_pengiriman) + vals['district_id_pengiriman'] = vals.get('district_id_pengiriman', self.district_id_pengiriman) + vals['subDistrict_id_pengiriman'] = vals.get('subDistrict_id_pengiriman', self.subDistrict_id_pengiriman) + vals['zip_pengiriman'] = vals.get('zip_pengiriman', self.zip_pengiriman) + vals['invoice_pic'] = vals.get('invoice_pic', self.invoice_pic) + vals['street_invoice'] = vals.get('street_invoice', self.street_invoice) + vals['state_id_invoice'] = vals.get('state_id_invoice', self.state_id_invoice) + vals['city_id_invoice'] = vals.get('city_id_invoice', self.city_id_invoice) + vals['district_id_invoice'] = vals.get('district_id_invoice', self.district_id_invoice) + vals['subDistrict_id_invoice'] = vals.get('subDistrict_id_invoice', self.subDistrict_id_invoice) + vals['zip_invoice'] = vals.get('zip_invoice', self.zip_invoice) + vals['tukar_invoice'] = vals.get('tukar_invoice', self.tukar_invoice) + vals['jadwal_bayar'] = vals.get('jadwal_bayar', self.jadwal_bayar) + vals['dokumen_pengiriman'] = vals.get('dokumen_pengiriman', self.dokumen_pengiriman) + vals['dokumen_pengiriman_input'] = vals.get('dokumen_pengiriman_input', self.dokumen_pengiriman_input) + vals['dokumen_invoice'] = vals.get('dokumen_invoice', self.dokumen_invoice) + + # Dokumen + vals['dokumen_npwp'] = vals.get('dokumen_npwp', self.dokumen_npwp) + vals['dokumen_sppkp'] = vals.get('dokumen_sppkp', self.dokumen_sppkp) + vals['dokumen_nib'] = vals.get('dokumen_nib', self.dokumen_nib) + vals['dokumen_siup'] = vals.get('dokumen_siup', self.dokumen_siup) + vals['dokumen_tdp'] = vals.get('dokumen_tdp', self.dokumen_tdp) + vals['dokumen_skdp'] = vals.get('dokumen_skdp', self.dokumen_skdp) + vals['dokumen_skt'] = vals.get('dokumen_skt', self.dokumen_skt) + vals['dokumen_akta_perubahan'] = vals.get('dokumen_akta_perubahan', self.dokumen_akta_perubahan) + vals['dokumen_ktp_dirut'] = vals.get('dokumen_ktp_dirut', self.dokumen_ktp_dirut) + vals['dokumen_akta_pendirian'] = vals.get('dokumen_akta_pendirian', self.dokumen_akta_pendirian) + vals['dokumen_laporan_keuangan'] = vals.get('dokumen_laporan_keuangan', self.dokumen_laporan_keuangan) + vals['dokumen_foto_kantor'] = vals.get('dokumen_foto_kantor', self.dokumen_foto_kantor) + vals['dokumen_tempat_bekerja'] = vals.get('dokumen_tempat_bekerja', self.dokumen_tempat_bekerja) # Simpan hanya field yang perlu di-update pada child vals_for_child = { @@ -144,7 +281,67 @@ class ResPartner(models.Model): 'sppkp': vals.get('sppkp'), 'alamat_lengkap_text': vals.get('alamat_lengkap_text'), 'industry_id': vals.get('industry_id'), - 'company_type_id': vals.get('company_type_id') + 'company_type_id': vals.get('company_type_id'), + 'supplier_ids': vals.get('supplier_ids'), + 'name_tempo': vals.get('name_tempo'), + 'industry_id_tempo': vals.get('industry_id_tempo'), + 'street_tempo': vals.get('street_tempo'), + 'state_id_tempo': vals.get('state_id_tempo'), + 'city_id_tempo': vals.get('city_id_tempo'), + 'zip_tempo': vals.get('zip_tempo'), + 'bank_name_tempo': vals.get('bank_name_tempo'), + 'account_name_tempo': vals.get('account_name_tempo'), + 'account_number_tempo': vals.get('account_number_tempo'), + 'website_tempo': vals.get('website_tempo'), + 'portal': vals.get('portal'), + 'estimasi_tempo': vals.get('estimasi_tempo'), + 'tempo_duration': vals.get('tempo_duration'), + 'tempo_limit': vals.get('tempo_limit'), + 'category_produk_ids': vals.get('category_produk_ids'), + 'direktur_name': vals.get('direktur_name'), + 'direktur_mobile': vals.get('direktur_mobile'), + 'direktur_email': vals.get('direktur_email'), + 'purchasing_name': vals.get('purchasing_name'), + 'purchasing_mobile': vals.get('purchasing_mobile'), + 'purchasing_email': vals.get('purchasing_email'), + 'finance_name': vals.get('finance_name'), + 'finance_mobile': vals.get('finance_mobile'), + 'finance_email': vals.get('finance_email'), + 'pic_name': vals.get('pic_name'), + 'street_pengiriman': vals.get('street_pengiriman'), + 'state_id_pengiriman': vals.get('state_id_pengiriman'), + 'city_id_pengiriman': vals.get('city_id_pengiriman'), + 'district_id_pengiriman': vals.get('district_id_pengiriman'), + 'subDistrict_id_pengiriman': vals.get('subDistrict_id_pengiriman'), + 'zip_pengiriman': vals.get('zip_pengiriman'), + 'invoice_pic': vals.get('invoice_pic'), + 'street_invoice': vals.get('street_invoice'), + 'state_id_invoice': vals.get('state_id_invoice'), + 'city_id_invoice': vals.get('city_id_invoice'), + 'district_id_invoice': vals.get('district_id_invoice'), + 'subDistrict_id_invoice': vals.get('subDistrict_id_invoice'), + 'zip_invoice': vals.get('zip_invoice'), + 'tukar_invoice': vals.get('tukar_invoice'), + 'jadwal_bayar': vals.get('jadwal_bayar'), + 'dokumen_pengiriman': vals.get('dokumen_pengiriman'), + 'dokumen_pengiriman_input': vals.get('dokumen_pengiriman_input'), + 'dokumen_invoice': vals.get('dokumen_invoice'), + 'dokumen_npwp': vals.get('dokumen_npwp'), + 'dokumen_sppkp': vals.get('dokumen_sppkp'), + 'dokumen_nib': vals.get('dokumen_nib'), + 'dokumen_siup': vals.get('dokumen_siup'), + 'dokumen_tdp': vals.get('dokumen_tdp'), + 'dokumen_skdp': vals.get('dokumen_skdp'), + 'dokumen_skt': vals.get('dokumen_skt'), + 'dokumen_akta_perubahan': vals.get('dokumen_akta_perubahan'), + 'dokumen_ktp_dirut': vals.get('dokumen_ktp_dirut'), + 'dokumen_akta_pendirian': vals.get('dokumen_akta_pendirian'), + 'dokumen_laporan_keuangan': vals.get('dokumen_laporan_keuangan'), + 'dokumen_foto_kantor': vals.get('dokumen_foto_kantor'), + 'dokumen_tempat_bekerja': vals.get('dokumen_tempat_bekerja'), + + # internal_notes + 'comment': vals.get('comment') } # Lakukan update pada semua child secara rekursif @@ -245,13 +442,10 @@ class ResPartner(models.Model): if self.customer_type == 'nonpkp': self.npwp = '00.000.000.0-000.000' - def get_check_tempo_partner(self): + def get_check_payment_term(self): self.ensure_one() partner = self.parent_id or self - if not partner.property_payment_term_id or 'Tempo' not in partner.property_payment_term_id.name: - return False - else: - return True + return partner.property_payment_term_id.name if partner.property_payment_term_id.id else 'Cash Before Delivery (C.B.D)' diff --git a/indoteknik_custom/models/res_users.py b/indoteknik_custom/models/res_users.py index 5e16aad1..fb9e8bfb 100755 --- a/indoteknik_custom/models/res_users.py +++ b/indoteknik_custom/models/res_users.py @@ -46,6 +46,11 @@ class ResUsers(models.Model): for user in self: template.send_mail(user.id, force_send=True) + def send_company_request_tempo_review(self): + template = self.env.ref('indoteknik_custom.mail_template_res_user_company_tempo_review') + for user in self: + template.send_mail(user.id, force_send=True) + def get_activation_token_url(self): base_url = self.env['ir.config_parameter'].get_param('site.base.url') return f'{base_url}/register?activation=token&token={self.activation_token}' diff --git a/indoteknik_custom/models/sale_order.py b/indoteknik_custom/models/sale_order.py index 7fc6d96a..7b2d9bf8 100755 --- a/indoteknik_custom/models/sale_order.py +++ b/indoteknik_custom/models/sale_order.py @@ -758,6 +758,7 @@ class SaleOrder(models.Model): raise UserError("Salesperson sudah tidak aktif, mohon diisi yang benar pada data SO dan Contact") def sale_order_approve(self): + self.check_credit_limit() 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() @@ -890,6 +891,37 @@ class SaleOrder(models.Model): 'email_to': salesperson_email, }).send() + def check_credit_limit(self): + for rec in self: + outstanding_amount = rec.outstanding_amount + check_credit_limit = False + ###### + block_stage = 0 + if rec.partner_id.parent_id: + if rec.partner_id.parent_id.active_limit and rec.partner_id.parent_id.enable_credit_limit: + check_credit_limit = True + else: + if rec.partner_id.active_limit and rec.partner_id.enable_credit_limit: + check_credit_limit = True + + term_days = 0 + for term_line in rec.payment_term_id.line_ids: + term_days += term_line.days + if term_days == 0: + check_credit_limit = False + + if check_credit_limit: + if rec.partner_id.parent_id: + block_stage = rec.partner_id.parent_id.blocking_stage or 0 + else: + block_stage = rec.partner_id.blocking_stage or 0 + + if (outstanding_amount + rec.amount_total) >= block_stage: + if block_stage != 0: + remaining_credit_limit = block_stage - outstanding_amount + 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 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')) @@ -999,8 +1031,9 @@ class SaleOrder(models.Model): if self.have_outstanding_invoice: raise UserError("Invoice harus di Cancel dahulu") - elif self.have_outstanding_picking: - raise UserError("DO harus di Cancel dahulu") + for line in self.order_line: + if line.qty_delivered > 0: + raise UserError("DO harus di-cancel terlebih dahulu.") if not self.web_approval: self.web_approval = 'company' @@ -1378,4 +1411,16 @@ class SaleOrder(models.Model): 'npwp': partner.npwp, 'email': partner.email, 'customer_type': partner.customer_type, - })
\ No newline at end of file + }) + + def write(self, vals): + for order in self: + if order.state in ['sale', 'cancel']: + if 'order_line' in vals: + new_lines = vals.get('order_line', []) + for command in new_lines: + if command[0] == 0: # A new line is being added + raise UserError( + "SO tidak dapat ditambahkan produk baru karena SO sudah menjadi sale order.") + res = super(SaleOrder, self).write(vals) + return res
\ No newline at end of file diff --git a/indoteknik_custom/models/sale_order_line.py b/indoteknik_custom/models/sale_order_line.py index a31ff569..29a046fa 100644 --- a/indoteknik_custom/models/sale_order_line.py +++ b/indoteknik_custom/models/sale_order_line.py @@ -38,6 +38,14 @@ class SaleOrderLine(models.Model): md_vendor_id = fields.Many2one('res.partner', string='MD Vendor', readonly=True) margin_md = fields.Float(string='Margin MD') qty_free_bu = fields.Float(string='Free BU', compute='_get_qty_free_bandengan') + desc_updatable = fields.Boolean(string='desc boolean', default=False, compute='_get_desc_updatable') + + def _get_desc_updatable(self): + for line in self: + if line.product_id.id != 417724: + line.desc_updatable = False + else: + line.desc_updatable = True def _get_qty_free_bandengan(self): for line in self: @@ -272,6 +280,10 @@ class SaleOrderLine(models.Model): (line.product_id.short_spesification if line.product_id.short_spesification else '') line.name = line_name line.weight = line.product_id.weight + if line.product_id.id != 417724: + line.desc_updatable = False + else: + line.desc_updatable = True @api.constrains('vendor_id') def _check_vendor_id(self): @@ -378,4 +390,14 @@ class SaleOrderLine(models.Model): if not line.product_id.product_tmpl_id.sale_ok: raise UserError('Product %s belum bisa dijual, harap hubungi finance' % line.product_id.display_name) if not line.vendor_id or not line.purchase_price and not line.display_type == 'line_note': - raise UserError(_('Isi Vendor dan Harga Beli sebelum Request Approval'))
\ No newline at end of file + raise UserError(_('Isi Vendor dan Harga Beli sebelum Request Approval')) + + @api.depends('state') + def _compute_product_updatable(self): + for line in self: + if line.state == 'draft': + line.product_updatable = True + # line.desc_updatable = True + else: + line.product_updatable = False + # line.desc_updatable = False diff --git a/indoteknik_custom/models/solr/apache_solr.py b/indoteknik_custom/models/solr/apache_solr.py index 6560c9b5..d111c1c1 100644 --- a/indoteknik_custom/models/solr/apache_solr.py +++ b/indoteknik_custom/models/solr/apache_solr.py @@ -22,7 +22,7 @@ class ApacheSolr(models.Model): url = '' if env == 'development': - url = 'http://192.168.23.5:8983/solr/' + url = 'http://localhost:8983/solr/' elif env == 'production': url = 'http://34.101.189.218:8983/solr/' diff --git a/indoteknik_custom/models/stock_immediate_transfer.py b/indoteknik_custom/models/stock_immediate_transfer.py new file mode 100644 index 00000000..4be0dff2 --- /dev/null +++ b/indoteknik_custom/models/stock_immediate_transfer.py @@ -0,0 +1,36 @@ +from odoo import models, api, _ +from odoo.exceptions import UserError + +class StockImmediateTransfer(models.TransientModel): + _inherit = 'stock.immediate.transfer' + + def process(self): + """Override process method to add send_mail_bills logic.""" + pickings_to_do = self.env['stock.picking'] + pickings_not_to_do = self.env['stock.picking'] + + for line in self.immediate_transfer_line_ids: + if line.to_immediate is True: + pickings_to_do |= line.picking_id + else: + pickings_not_to_do |= line.picking_id + + for picking in pickings_to_do: + picking.send_mail_bills() + # If still in draft => confirm and assign + if picking.state == 'draft': + picking.action_confirm() + if picking.state != 'assigned': + picking.action_assign() + if picking.state != 'assigned': + raise UserError(_("Could not reserve all requested products. Please use the 'Mark as Todo' button to handle the reservation manually.")) + for move in picking.move_lines.filtered(lambda m: m.state not in ['done', 'cancel']): + for move_line in move.move_line_ids: + move_line.qty_done = move_line.product_uom_qty + + pickings_to_validate = self.env.context.get('button_validate_picking_ids') + if pickings_to_validate: + pickings_to_validate = self.env['stock.picking'].browse(pickings_to_validate) + pickings_to_validate = pickings_to_validate - pickings_not_to_do + return pickings_to_validate.with_context(skip_immediate=True).button_validate() + return True diff --git a/indoteknik_custom/models/stock_move.py b/indoteknik_custom/models/stock_move.py index ac2e3cc0..e1d4e74c 100644 --- a/indoteknik_custom/models/stock_move.py +++ b/indoteknik_custom/models/stock_move.py @@ -7,6 +7,27 @@ class StockMove(models.Model): line_no = fields.Integer('No', default=0) sale_id = fields.Many2one('sale.order', string='SO') + print_barcode = fields.Boolean( + string="Print Barcode", + default=lambda self: self.product_id.print_barcode, + ) + qr_code_variant = fields.Binary("QR Code Variant", compute='_compute_qr_code_variant') + + def _compute_qr_code_variant(self): + for rec in self: + if rec.print_barcode and rec.print_barcode == True and rec.product_id and rec.product_id.qr_code_variant: + rec.qr_code_variant = rec.product_id.qr_code_variant + else: + rec.qr_code_variant = False + + + def write(self, vals): + res = super(StockMove, self).write(vals) + if 'print_barcode' in vals: + for line in self: + if line.product_id: + line.product_id.print_barcode = vals['print_barcode'] + return res def _do_unreserve(self, product=None, quantity=False): moves_to_unreserve = OrderedSet() diff --git a/indoteknik_custom/models/stock_picking.py b/indoteknik_custom/models/stock_picking.py index e6506a0b..cd330aeb 100644 --- a/indoteknik_custom/models/stock_picking.py +++ b/indoteknik_custom/models/stock_picking.py @@ -6,10 +6,17 @@ from itertools import groupby import pytz, requests, json, requests from dateutil import parser import datetime - +import hmac +import hashlib +import base64 +import requests +import time +import logging +_logger = logging.getLogger(__name__) class StockPicking(models.Model): _inherit = 'stock.picking' + # check_product_lines = fields.One2many('check.product', 'picking_id', string='Check Product', auto_join=True) is_internal_use = fields.Boolean('Internal Use', help='flag which is internal use or not') account_id = fields.Many2one('account.account', string='Account') efaktur_id = fields.Many2one('vit.efaktur', string='Faktur Pajak') @@ -115,6 +122,19 @@ class StockPicking(models.Model): ], string='Status Reserve', readonly=True, tracking=True, help="The current state of the stock picking.") notee = fields.Text(string="Note") + @api.model + def _compute_dokumen_tanda_terima(self): + for picking in self: + picking.dokumen_tanda_terima = picking.partner_id.dokumen_pengiriman + + @api.model + def _compute_dokumen_pengiriman(self): + for picking in self: + picking.dokumen_pengiriman = picking.partner_id.dokumen_pengiriman_input + + dokumen_tanda_terima = fields.Char(string='Dokumen Tanda Terima yang Diberikan Pada Saat Pengiriman Barang', readonly=True, compute=_compute_dokumen_tanda_terima) + dokumen_pengiriman = fields.Char(string='Dokumen yang Dibawa Saat Pengiriman Barang', readonly=True, compute=_compute_dokumen_pengiriman) + # Envio Tracking Section envio_id = fields.Char(string="Envio ID", readonly=True) envio_code = fields.Char(string="Envio Code", readonly=True) @@ -134,6 +154,86 @@ class StockPicking(models.Model): envio_latest_longitude = fields.Float(string="Log Longitude", readonly=True) tracking_by = fields.Many2one('res.users', string='Tracking By', readonly=True, tracking=True) + # Lalamove Section + lalamove_order_id = fields.Char(string="Lalamove Order ID", copy=False) + lalamove_address = fields.Char(string="Lalamove Address") + lalamove_name = fields.Char(string="Lalamove Name") + lalamove_phone = fields.Char(string="Lalamove Phone") + lalamove_status = fields.Char(string="Lalamove Status") + lalamove_delivered_at = fields.Datetime(string="Lalamove Delivered At") + lalamove_data = fields.Text(string="Lalamove Data", readonly=True) + lalamove_image_url = fields.Char(string="Lalamove Image URL") + lalamove_image_html = fields.Html(string="Lalamove Image", compute="_compute_lalamove_image_html") + + def _compute_lalamove_image_html(self): + for record in self: + if record.lalamove_image_url: + record.lalamove_image_html = f'<img src="{record.lalamove_image_url}" width="300" height="300"/>' + else: + record.lalamove_image_html = "No image available." + + def action_fetch_lalamove_order(self): + pickings = self.env['stock.picking'].search([ + ('picking_type_code', '=', 'outgoing'), + ('state', '=', 'done'), + ('carrier_id', '=', 9) + ]) + for picking in pickings: + try: + order_id = picking.lalamove_order_id + apikey = self.env['ir.config_parameter'].sudo().get_param('lalamove.apikey') + secret = self.env['ir.config_parameter'].sudo().get_param('lalamove.secret') + market = self.env['ir.config_parameter'].sudo().get_param('lalamove.market', default='ID') + + order_data = picking.get_lalamove_order(order_id, apikey, secret, market) + picking.lalamove_data = order_data + except Exception as e: + _logger.error(f"Error fetching Lalamove order for picking {picking.id}: {str(e)}") + continue + + def get_lalamove_order(self, order_id, apikey, secret, market): + timestamp = str(int(time.time() * 1000)) + message = f"{timestamp}\r\nGET\r\n/v3/orders/{order_id}\r\n\r\n" + signature = hmac.new(secret.encode('utf-8'), message.encode('utf-8'), hashlib.sha256).hexdigest() + + headers = { + "Content-Type": "application/json", + "Authorization": f"hmac {apikey}:{timestamp}:{signature}", + "Market": market + } + + url = f"https://rest.lalamove.com/v3/orders/{order_id}" + response = requests.get(url, headers=headers) + + if response.status_code == 200: + data = response.json() + stops = data.get("data", {}).get("stops", []) + + for stop in stops: + pod = stop.get("POD", {}) + if pod.get("status") == "DELIVERED": + image_url = pod.get("image") # Sesuaikan jika key berbeda + self.lalamove_image_url = image_url + + address = stop.get("address") + name = stop.get("name") + phone = stop.get("phone") + delivered_at = pod.get("deliveredAt") + + delivered_at_dt = self._convert_to_datetime(delivered_at) + + self.lalamove_address = address + self.lalamove_name = name + self.lalamove_phone = phone + self.lalamove_status = pod.get("status") + self.lalamove_delivered_at = delivered_at_dt + return data + + raise UserError("No delivered data found in Lalamove response.") + else: + raise UserError(f"Error {response.status_code}: {response.text}") + + def _convert_to_wib(self, date_str): """ Mengonversi string waktu ISO 8601 ke format waktu Indonesia (WIB) @@ -661,13 +761,13 @@ class StockPicking(models.Model): if not self.env.user.is_logistic_approver and self.env.context.get('active_model') == 'stock.picking': if self.origin and 'Return of' in self.origin: raise UserError("Button ini hanya untuk Logistik") - + if self.picking_type_code == 'internal': self.check_qty_done_stock() if self._name != 'stock.picking': return super(StockPicking, self).button_validate() - + if not self.picking_code: self.picking_code = self.env['ir.sequence'].next_by_code('stock.picking.code') or '0' @@ -681,15 +781,10 @@ class StockPicking(models.Model): raise UserError("Harus di Approve oleh Accounting") if self.picking_type_id.id == 28 and not self.env.user.is_logistic_approver: - raise UserError("Harus di Approve oleh Logistik") + raise UserError("Harus di Approve oleh Logistik") if self.location_dest_id.id == 47 and not self.env.user.is_purchasing_manager: - raise UserError("Transfer ke gudang selisih harus di approve Rafly Hanggara") - - # if self.group_id.sale_id: - # if self.group_id.sale_id.payment_link_midtrans: - # if self.group_id.sale_id.payment_status != 'settlement' and self.group_id.sale_id.state == 'draft': - # raise UserError('Uang belum masuk (settlement), mohon konfirmasi ke sales atau finance') + raise UserError("Transfer ke gudang selisih harus di approve Rafly Hanggara") if self.is_internal_use: self.approval_status = 'approved' @@ -707,7 +802,7 @@ class StockPicking(models.Model): if not self.date_reserved: current_time = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') self.date_reserved = current_time - + self.validation_minus_onhand_quantity() self.responsible = self.env.user.id res = super(StockPicking, self).button_validate() @@ -715,6 +810,59 @@ class StockPicking(models.Model): self.date_done = datetime.datetime.utcnow() self.state_reserve = 'done' return res + + + def send_mail_bills(self): + if self.picking_type_code == 'incoming' and self.purchase_id: + template = self.env.ref('indoteknik_custom.mail_template_invoice_po_document') + if template and self.purchase_id: + # Render email body + email_values = template.sudo().generate_email( + res_ids=[self.purchase_id.id], + fields=['body_html'] + ) + rendered_body = email_values.get(self.purchase_id.id, {}).get('body_html', '') + + # Render report dengan XML ID + report = self.env.ref('purchase.action_report_purchase_order') # Gunakan XML ID laporan + if not report: + raise UserError("Laporan dengan XML ID 'purchase.action_report_purchase_order' tidak ditemukan.") + + # Render laporan ke PDF + pdf_content, _ = report._render_qweb_pdf([self.purchase_id.id]) + report_content = base64.b64encode(pdf_content).decode('utf-8') + + # Kirim email menggunakan template + email_sent = template.sudo().send_mail(self.purchase_id.id, force_send=True) + + if email_sent: + # Buat attachment untuk laporan + attachment = self.env['ir.attachment'].create({ + 'name': self.purchase_id.name or "Laporan Invoice.pdf", + 'type': 'binary', + 'datas': report_content, + 'res_model': 'purchase.order', + 'res_id': self.purchase_id.id, + 'mimetype': 'application/pdf', + }) + + # Siapkan data untuk mail.compose.message + compose_values = { + 'subject': "Pengiriman Email Invoice", + 'body': rendered_body, + 'attachment_ids': [(4, attachment.id)], + 'res_id': self.purchase_id.id, + 'model': 'purchase.order', + } + + # Buat mail.compose.message + compose_message = self.env['mail.compose.message'].create(compose_values) + + # Kirim pesan melalui wizard + compose_message.action_send_mail() + + return True + def action_cancel(self): if not self.env.user.is_logistic_approver and self.env.context.get('active_model') == 'stock.picking': if self.origin and 'Return of' in self.origin: @@ -858,4 +1006,50 @@ class StockPicking(models.Model): formatted_fastest_eta = fastest_eta.strftime(format_time_fastest) formatted_longest_eta = longest_eta.strftime(format_time) - return f'{formatted_fastest_eta} - {formatted_longest_eta}'
\ No newline at end of file + return f'{formatted_fastest_eta} - {formatted_longest_eta}' + +# class CheckProduct(models.Model): +# _name = 'check.product' +# _description = 'Check Product' +# _order = 'picking_id, id' + +# picking_id = fields.Many2one('stock.picking', string='Picking Reference', required=True, ondelete='cascade', index=True, copy=False) +# product_id = fields.Many2one('product.product', string='Product') + + +# @api.constrains('product_id') +# def check_product_validity(self): +# """ +# Validate if the product exists in the related stock.picking's move_ids_without_package +# and ensure that the product's quantity does not exceed the available product_uom_qty. +# """ +# for record in self: +# if not record.picking_id or not record.product_id: +# continue + +# # Filter move lines in the related picking for the selected product +# moves = record.picking_id.move_ids_without_package.filtered( +# lambda move: move.product_id.id == record.product_id.id +# ) + +# if not moves: +# raise UserError(( +# "The product '%s' is not available in the related stock picking's moves. " +# "Please check and try again." +# ) % record.product_id.display_name) + +# # Calculate the total entries for the product in check.product for the same picking +# product_entries_count = self.search_count([ +# ('picking_id', '=', record.picking_id.id), +# ('product_id', '=', record.product_id.id) +# ]) + +# # Sum the product_uom_qty for all relevant moves +# total_qty_in_moves = sum(moves.mapped('product_uom_qty')) + +# # Compare the count of entries against the available quantity +# if product_entries_count > total_qty_in_moves: +# raise UserError(( +# "The product '%s' exceeds the allowable quantity (%s) in the related stock picking's moves. " +# "You can only add it %s times." +# ) % (record.product_id.display_name, total_qty_in_moves, total_qty_in_moves)) diff --git a/indoteknik_custom/models/user_company_request.py b/indoteknik_custom/models/user_company_request.py index dd9a35c1..3de3d751 100644 --- a/indoteknik_custom/models/user_company_request.py +++ b/indoteknik_custom/models/user_company_request.py @@ -64,6 +64,7 @@ class UserCompanyRequest(models.Model): user.parent_name = self.user_input is_approve = vals.get('is_approve') is_internal_input = vals.get('internal_input') + is_company_id = vals.get('user_company_id') if self.is_approve and is_approve: raise UserError('Tidak dapat mengubah approval yang sudah diisi') @@ -71,20 +72,35 @@ class UserCompanyRequest(models.Model): if self.user_company_id.nama_wajib_pajak == self.user_company_id.name: self.user_company_id.nama_wajib_pajak = is_internal_input self.user_company_id.name = is_internal_input + user_company_id = [] + if is_company_id: + user_company_id = request.env['res.partner'].search([('id', '=', is_company_id)], limit=1) + # self.user_company_id.customer_type = self.similar_company_ids.customer_type + # self.user_company_id.npwp = self.similar_company_ids.npwp + # self.user_company_id.sppkp = self.similar_company_ids.sppkp + # self.user_company_id.nama_wajib_pajak = self.similar_company_ids.nama_wajib_pajak + # self.user_company_id.alamat_lengkap_text = self.similar_company_ids.alamat_lengkap_text + # self.user_company_id.industry_id = self.similar_company_ids.industry_id + # self.user_company_id.company_type_id = self.similar_company_ids.company_type_id + # self.user_company_id.user_id = self.similar_company_ids.user_id + # self.user_company_id.property_account_receivable_id = self.similar_company_ids.property_account_receivable_id + # self.user_company_id.property_account_payable_id = self.similar_company_ids.property_account_payable_id if not self.is_approve and is_approve: if is_approve == 'approved': - self.user_id.parent_id = vals.get('user_company_id') if vals.get('user_company_id') else self.user_company_id.id - self.user_id.customer_type = self.user_company_id.customer_type - self.user_id.npwp = self.user_company_id.npwp - self.user_id.sppkp = self.user_company_id.sppkp - self.user_id.nama_wajib_pajak = self.user_company_id.nama_wajib_pajak - self.user_id.alamat_lengkap_text = self.user_company_id.alamat_lengkap_text - self.user_id.industry_id = self.user_company_id.industry_id.id - self.user_id.company_type_id = self.user_company_id.company_type_id.id - self.user_id.user_id = self.user_company_id.user_id - self.user_id.property_account_receivable_id = self.user_company_id.property_account_receivable_id - self.user_id.property_account_payable_id = self.user_company_id.property_account_payable_id + self.user_id.parent_id = user_company_id if user_company_id else self.user_company_id + self.user_id.customer_type = user_company_id.customer_type if user_company_id else self.user_company_id.customer_type + self.user_id.npwp = user_company_id.npwp if user_company_id else self.user_company_id.npwp + self.user_id.sppkp = user_company_id.sppkp if user_company_id else self.user_company_id.sppkp + self.user_id.nama_wajib_pajak = user_company_id.nama_wajib_pajak if user_company_id else self.user_company_id.nama_wajib_pajak + self.user_id.alamat_lengkap_text = user_company_id.alamat_lengkap_text if user_company_id else self.user_company_id.alamat_lengkap_text + self.user_id.industry_id = user_company_id.industry_id.id if user_company_id else self.user_company_id.industry_id + self.user_id.company_type_id = user_company_id.company_type_id.id if user_company_id else self.user_company_id.company_type_id + self.user_id.user_id = user_company_id.user_id if user_company_id else self.user_company_id.user_id + self.user_id.property_account_receivable_id = user_company_id.property_account_receivable_id if user_company_id else self.user_company_id.property_account_receivable_id + self.user_id.property_account_payable_id = user_company_id.property_account_payable_id if user_company_id else self.user_company_id.property_account_payable_id + self.user_id.property_payment_term_id = user_company_id.property_payment_term_id if user_company_id else self.user_company_id.property_payment_term_id + self.user_id.property_supplier_payment_term_id = user_company_id.property_supplier_payment_term_id if user_company_id else self.user_company_id.property_supplier_payment_term_id self.user_company_id.active = True user.send_company_request_approve_mail() else: diff --git a/indoteknik_custom/models/user_pengajuan_tempo.py b/indoteknik_custom/models/user_pengajuan_tempo.py new file mode 100644 index 00000000..0fdcdbeb --- /dev/null +++ b/indoteknik_custom/models/user_pengajuan_tempo.py @@ -0,0 +1,134 @@ +from odoo import models, fields, api +from datetime import datetime, timedelta + + +# class IrAttachment(models.Model): +# _inherit = 'ir.attachment' +# +# @api.model +# def create(self, vals): +# attachment = super(IrAttachment, self).create(vals) +# if attachment: +# base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url') +# attachment.url = f"/web/content/{attachment.id}" +# return attachment + + +class UserPengajuanTempo(models.Model): + _name = 'user.pengajuan.tempo' + _inherit = ['mail.thread', 'mail.activity.mixin'] + partner_id = fields.Char() + _description = 'User Pengajuan Tempo' + + name = fields.Char(string='Name') + + # informasi perusahaan + # name_tempo = fields.Many2one( + # 'res.partner', string='Nama Perusahaan', + # readonly=True, required=True, + # states={'draft': [('readonly', False)], 'sent': [('readonly', False)], 'sale': [('readonly', False)]}, + # domain="['|', ('company_id', '=', False), ('company_id', '=', company_id)]", + # tracking=True, # Menambahkan tracking=True + # ) + name_tempo = fields.Many2one( + 'res.partner', string='Nama Perusahaan', + tracking=True, # Menambahkan tracking=True + ) + user_id = fields.Many2one('res.users', string='User') + industry_id_tempo = fields.Many2one('res.partner.industry', 'Customer Industry', readonly=True) + street_tempo = fields.Char(string="Alamat Perusahaan") + state_id_tempo = fields.Many2one('res.country.state', string='State') + city_id_tempo = fields.Many2one('vit.kota', string='City') + district_id_tempo = fields.Many2one('vit.kecamatan', string='Kecamatan') + subDistrict_id_tempo = fields.Many2one('vit.kelurahan', string='Kelurahan') + zip_tempo = fields.Char(string="Zip") + mobile_tempo = fields.Char(string="No. Telfon Perusahaan") + bank_name_tempo = fields.Char(string="Nama Bank") + account_name_tempo = fields.Char(string="Nama Rekening") + account_number_tempo = fields.Char(string="Nomor Rekening Bank") + website_tempo = fields.Char(string='Website') + portal = fields.Boolean(string='Portal Website') + bersedia = fields.Char(string='Website') + estimasi_tempo = fields.Char(string='Estimasi Pembelian Pertahun') + tempo_duration = fields.Many2one('account.payment.term', string='Durasi Tempo') + tempo_limit = fields.Char(string='Limit Tempo') + category_produk_ids = fields.Many2many('product.public.category', string='Kategori Produk yang Digunakan', domain=lambda self: self._get_default_category_domain()) + + @api.model + def _get_default_category_domain(self): + return [('parent_id', '=', False)] + + # Kontak Perusahaan + direktur_tittle = fields.Char(string='tittle Direktur') + direktur_name = fields.Char(string='Nama Lengkap Direktur') + direktur_mobile = fields.Char(string='No. Telpon Direktur') + direktur_email = fields.Char(string='Email Direktur') + purchasing_tittle = fields.Char(string='tittle Purchasing') + purchasing_name = fields.Char(string='Nama Purchasing') + purchasing_mobile = fields.Char(string='No. Telpon Purchasing') + purchasing_email = fields.Char(string='Email Purchasing') + finance_tittle = fields.Char(string='tittle Finance') + finance_name = fields.Char(string='Nama Finance') + finance_mobile = fields.Char(string='No. Telpon Finance') + finance_email = fields.Char(string='Email Finance') + + # Pengiriman + pic_tittle = fields.Char(string='Tittle PIC Penerimaan Barang') + pic_name = fields.Char(string='Nama PIC Penerimaan Barang') + street_pengiriman = fields.Char(string="Alamat Perusahaan") + state_id_pengiriman = fields.Many2one('res.country.state', string='State') + city_id_pengiriman = fields.Many2one('vit.kota', string='City') + district_id_pengiriman = fields.Many2one('vit.kecamatan', string='Kecamatan') + subDistrict_id_pengiriman = fields.Many2one('vit.kelurahan', string='Kelurahan') + zip_pengiriman = fields.Char(string="Zip") + invoice_pic_tittle = fields.Char(string='Tittle PIC Penerimaan Invoice') + invoice_pic = fields.Char(string='Nama PIC Penerimaan Invoice') + street_invoice = fields.Char(string="Alamat Perusahaan") + state_id_invoice = fields.Many2one('res.country.state', string='State') + city_id_invoice = fields.Many2one('vit.kota', string='City') + district_id_invoice = fields.Many2one('vit.kecamatan', string='Kecamatan') + subDistrict_id_invoice = fields.Many2one('vit.kelurahan', string='Kelurahan') + zip_invoice = fields.Char(string="Zip") + tukar_invoice = fields.Char(string='Jadwal Penukaran Invoice') + jadwal_bayar = fields.Char(string='Jadwal Pembayaran') + dokumen_pengiriman = fields.Char(string='Dokumen Tanda Terima yang Diberikan Pada Saat Pengiriman Barang') + dokumen_kirim_input = fields.Char(string='Dokumen lain yang diterima saat pengiriman barang') + dokumen_pengiriman_input = fields.Char(string='Dokumen yang Dibawa Saat Pengiriman Barang') + dokumen_invoice = fields.Char(string='Dokumen yang dilampirkan saat Pengiriman Invoice') + is_same_address = fields.Boolean(string="Same Address pengiriman invoicr dan alamat pengiriman barang") + is_same_address_street = fields.Boolean(string="Same Address pengiriman barang dan alamat bisnis") + + # Referensi + supplier_ids = fields.Many2many('user.pengajuan.tempo.line', string="Suppliers") + + #Dokumen + dokumen_nib = fields.Many2many('ir.attachment', 'pengajuan_dokumen_nib_rel', string="NIB", tracking=True, track_visibility="onchange") + dokumen_npwp = fields.Many2many('ir.attachment', 'pengajuan_dokumen_npwp_rel', string="NPWP Perusahaan", tracking=True) + dokumen_sppkp = fields.Many2many('ir.attachment', 'pengajuan_dokumen_sppkp_rel', string="SPPKP Perusahaan", tracking=True) + dokumen_siup = fields.Many2many('ir.attachment', 'pengajuan_dokumen_siup_rel', string="SIUP Perusahaan", tracking=True) + dokumen_tdp = fields.Many2many('ir.attachment', 'pengajuan_dokumen_tdp_rel', string="TDP Perusahaan", tracking=True) + dokumen_skdp = fields.Many2many('ir.attachment', 'pengajuan_dokumen_skdp_rel', string="SKDP Perusahaan", tracking=True) + dokumen_skt = fields.Many2many('ir.attachment', 'pengajuan_dokumen_skt_rel', string="SKT Perusahaan", tracking=True) + dokumen_akta_perubahan = fields.Many2many('ir.attachment', 'pengajuan_dokumen_akta_perubahan_rel', + string="Akta Perubahan", tracking=True) + dokumen_ktp_dirut = fields.Many2many('ir.attachment', 'pengajuan_dokumen_ktp_dirut_rel', + string="KTP Dirut/Direktur", tracking=True) + dokumen_akta_pendirian = fields.Many2many('ir.attachment', 'pengajuan_dokumen_angkta_pendirian_rel', + string="Akta Pendirian", tracking=True) + dokumen_laporan_keuangan = fields.Many2many('ir.attachment', 'pengajuan_dokumen_laporan_keuangan_rel', + string="Laporan Keuangan", tracking=True) + dokumen_foto_kantor = fields.Many2many('ir.attachment', 'pengajuan_dokumen_foto_kantor_rel', + string=" Foto Kantor (Tampak Depan)", tracking=True) + dokumen_tempat_bekerja = fields.Many2many('ir.attachment', 'pengajuan_dokumen_tempat_bekerja_rel', + string="Tempat Bekerja", tracking=True) + + @api.depends('name', 'name_tempo') + def name_get(self): + result = [] + for record in self: + if record.name_tempo: + display_name = f"DETAIL FORM TEMPO - {record.name_tempo.name}" + else: + display_name = "DETAIL FORM TEMPO" + result.append((record.id, display_name)) + return result diff --git a/indoteknik_custom/models/user_pengajuan_tempo_line.py b/indoteknik_custom/models/user_pengajuan_tempo_line.py new file mode 100644 index 00000000..db519ed6 --- /dev/null +++ b/indoteknik_custom/models/user_pengajuan_tempo_line.py @@ -0,0 +1,12 @@ +from odoo import models, fields + + +class PengajuanTempoLine(models.Model): + _name = 'user.pengajuan.tempo.line' + + # Fields untuk tabel supplier + name_supplier = fields.Char(string="Nama Supplier") + pic_name = fields.Char(string="PIC") + phone = fields.Char(string="Telepon") + tempo_duration = fields.Char(string="Durasi Tempo") + credit_limit = fields.Char(string="Credit Limit")
\ No newline at end of file diff --git a/indoteknik_custom/models/user_pengajuan_tempo_request.py b/indoteknik_custom/models/user_pengajuan_tempo_request.py new file mode 100644 index 00000000..f5261cd4 --- /dev/null +++ b/indoteknik_custom/models/user_pengajuan_tempo_request.py @@ -0,0 +1,630 @@ +from odoo import models, fields, api, _ +from odoo.exceptions import UserError +from odoo.http import request + +class RejectReasonWizard(models.TransientModel): + _name = 'reject.reason.wizard' + _description = 'Wizard for Reject Reason' + + request_id = fields.Many2one('user.pengajuan.tempo.request', string='Request') + reason_reject = fields.Text(string='Reason for Rejection', required=True) + + def confirm_reject(self): + tempo = self.request_id + if tempo: + tempo.write({'reason_reject': self.reason_reject}) + tempo.state_tempo = 'reject' + template = self.env.ref('indoteknik_custom.mail_template_res_user_company_tempo_reject') + template.send_mail(tempo.id, force_send=True) + return {'type': 'ir.actions.act_window_close'} +class ConfirmApprovalWizard(models.TransientModel): + _name = 'confirm.approval.wizard' + _description = 'Wizard Konfirmasi Approval' + + tempo_id = fields.Many2one('user.pengajuan.tempo.request', string='Tempo', required=True) + + def confirm_approval(self): + tempo = self.tempo_id + if tempo.state_tempo == 'draft': + tempo.state_tempo = 'approval_sales' + template = self.env.ref('indoteknik_custom.mail_template_res_user_company_tempo_approved_by_sales') + template.send_mail(tempo.id, force_send=True) + elif tempo.state_tempo == 'approval_sales': + tempo.state_tempo = 'approval_finance' + template = self.env.ref('indoteknik_custom.mail_template_res_user_company_tempo_to_aprove_director') + template.send_mail(tempo.id, force_send=True) + elif tempo.state_tempo == 'approval_finance': + tempo.state_tempo = 'approval_director' + + + +class UserPengajuanTempoRequest(models.Model): + _name = 'user.pengajuan.tempo.request' + _inherit = ['mail.thread', 'mail.activity.mixin'] + _rec_name = 'user_id' + + user_id = fields.Many2one('res.partner', string='User') + user_company_id = fields.Many2one('res.partner', string='Company') + pengajuan_tempo_id = fields.Many2one('user.pengajuan.tempo', string='Form Tempo') + tempo_duration = fields.Many2one('account.payment.term', string='Durasi Tempo', tracking=3, domain=[('id', 'in', [24, 25, 29, 32])]) + tempo_limit = fields.Integer(string='Limit Tempo', tracking=3) + state_tempo = fields.Selection([ + ('draft', 'Pengajuan Tempo'), + ('approval_sales', 'Approved by Sales Manager'), + ('approval_finance', 'Approved by Finance'), + ('approval_director', 'Approved by Director'), + ('reject', 'Rejected'), + ], string='Status', readonly=True, copy=False, index=True, track_visibility='onchange', default='draft') + reason_reject = fields.Char(string='Limit Tempo') + + # informasi perusahaan + name_tempo = fields.Many2one('res.partner', string='Nama Perusahaan', related='pengajuan_tempo_id.name_tempo', store=True, tracking=True, readonly=False) + industry_id_tempo = fields.Many2one('res.partner.industry', 'Customer Industry', related='pengajuan_tempo_id.industry_id_tempo',store=True, tracking=True, readonly=False) + street_tempo = fields.Char(string="Alamat Perusahaan", related='pengajuan_tempo_id.street_tempo', store=True, tracking=True, readonly=False) + state_id_tempo = fields.Many2one('res.country.state', string='State', related='pengajuan_tempo_id.state_id_tempo', store=True, tracking=True, readonly=False) + city_id_tempo = fields.Many2one('vit.kota', string='City', related='pengajuan_tempo_id.city_id_tempo', store=True, tracking=True, readonly=False) + zip_tempo = fields.Char(string="Zip", related='pengajuan_tempo_id.zip_tempo', store=True, tracking=True, readonly=False) + mobile_tempo = fields.Char(string="No. Telfon Perusahaan", related='pengajuan_tempo_id.mobile_tempo', store=True, tracking=True, readonly=False) + bank_name_tempo = fields.Char(string="Nama Bank", related='pengajuan_tempo_id.bank_name_tempo', store=True, tracking=True, readonly=False) + account_name_tempo = fields.Char(string="Nama Rekening", related='pengajuan_tempo_id.account_name_tempo', store=True, tracking=True, readonly=False) + account_number_tempo = fields.Char(string="Nomor Rekening Bank", related='pengajuan_tempo_id.account_number_tempo', store=True, tracking=True, readonly=False) + website_tempo = fields.Char(string='Website', related='pengajuan_tempo_id.website_tempo', store=True, tracking=True, readonly=False) + portal = fields.Boolean(string='Portal Website', related='pengajuan_tempo_id.portal', store=True, tracking=True, readonly=False) + estimasi_tempo = fields.Char(string='Estimasi Pembelian Pertahun', related='pengajuan_tempo_id.estimasi_tempo', store=True, tracking=True, readonly=False) + tempo_duration_origin = fields.Many2one('account.payment.term', string='Durasi Tempo', related='pengajuan_tempo_id.tempo_duration', store=True, tracking=True, readonly=False, domain=[('id', 'in', [24, 25, 29, 32])]) + tempo_limit_origin = fields.Char(string='Limit Tempo', related='pengajuan_tempo_id.tempo_limit' , store=True, tracking=True, readonly=False) + category_produk_ids = fields.Many2many('product.public.category', string='Kategori Produk yang Digunakan', related='pengajuan_tempo_id.category_produk_ids', readonly=False) + + # Kontak Perusahaan + direktur_name = fields.Char(string='Nama Lengkap Direktur', related='pengajuan_tempo_id.direktur_name', store=True, readonly=False) + direktur_mobile = fields.Char(string='No. Telpon Direktur', related='pengajuan_tempo_id.direktur_mobile', store=True, readonly=False) + direktur_email = fields.Char(string='Email Direktur', related='pengajuan_tempo_id.direktur_email', store=True, readonly=False) + purchasing_name = fields.Char(string='Nama Purchasing', related='pengajuan_tempo_id.purchasing_name', store=True, readonly=False) + purchasing_mobile = fields.Char(string='No. Telpon Purchasing', related='pengajuan_tempo_id.purchasing_mobile', store=True, readonly=False) + purchasing_email = fields.Char(string='Email Purchasing', related='pengajuan_tempo_id.purchasing_email', store=True, readonly=False) + finance_name = fields.Char(string='Nama Finance', related='pengajuan_tempo_id.finance_name', store=True, readonly=False) + finance_mobile = fields.Char(string='No. Telpon Finance', related='pengajuan_tempo_id.finance_mobile', store=True, readonly=False) + finance_email = fields.Char(string='Email Finance', related='pengajuan_tempo_id.finance_email', store=True, readonly=False) + + # Pengiriman + pic_tittle = fields.Char(string='Tittle PIC Penerimaan Barang', related='pengajuan_tempo_id.pic_tittle', store=True, readonly=False) + pic_name = fields.Char(string='Nama PIC Penerimaan Barang', related='pengajuan_tempo_id.pic_name', store=True, readonly=False) + street_pengiriman = fields.Char(string="Alamat Perusahaan", related='pengajuan_tempo_id.street_pengiriman', store=True, readonly=False) + state_id_pengiriman = fields.Many2one('res.country.state', string='State', related='pengajuan_tempo_id.state_id_pengiriman', store=True, readonly=False) + city_id_pengiriman = fields.Many2one('vit.kota', string='City', related='pengajuan_tempo_id.city_id_pengiriman', store=True, readonly=False) + district_id_pengiriman = fields.Many2one('vit.kecamatan', string='Kecamatan',related='pengajuan_tempo_id.district_id_pengiriman', store=True, readonly=False) + subDistrict_id_pengiriman = fields.Many2one('vit.kelurahan', string='Kelurahan', related='pengajuan_tempo_id.subDistrict_id_pengiriman', store=True, readonly=False) + zip_pengiriman = fields.Char(string="Zip", related='pengajuan_tempo_id.zip_pengiriman', store=True, readonly=False) + invoice_pic_tittle = fields.Char(string='Tittle PIC Penerimaan Invoice', related='pengajuan_tempo_id.invoice_pic_tittle', store=True, readonly=False) + invoice_pic = fields.Char(string='Nama PIC Penerimaan Invoice', related='pengajuan_tempo_id.invoice_pic', store=True, readonly=False) + street_invoice = fields.Char(string="Alamat Perusahaan", related='pengajuan_tempo_id.street_invoice', store=True, readonly=False) + state_id_invoice = fields.Many2one('res.country.state', string='State', related='pengajuan_tempo_id.state_id_invoice', store=True, readonly=False) + city_id_invoice = fields.Many2one('vit.kota', string='City', related='pengajuan_tempo_id.city_id_invoice', store=True, readonly=False) + district_id_invoice = fields.Many2one('vit.kecamatan', string='Kecamatan', related='pengajuan_tempo_id.district_id_invoice', store=True, readonly=False) + subDistrict_id_invoice = fields.Many2one('vit.kelurahan', string='Kelurahan', related='pengajuan_tempo_id.subDistrict_id_invoice', store=True, readonly=False) + zip_invoice = fields.Char(string="Zip", related='pengajuan_tempo_id.zip_invoice', store=True, readonly=False) + tukar_invoice = fields.Char(string='Jadwal Penukaran Invoice', related='pengajuan_tempo_id.tukar_invoice', store=True, readonly=False) + jadwal_bayar = fields.Char(string='Jadwal Pembayaran', related='pengajuan_tempo_id.jadwal_bayar', store=True, readonly=False) + dokumen_pengiriman = fields.Char(string='Dokumen Tanda Terima yang Diberikan Pada Saat Pengiriman Barang', related='pengajuan_tempo_id.dokumen_pengiriman', store=True, readonly=False) + dokumen_pengiriman_input = fields.Char(string='Dokumen yang dibawa saat pengiriman barang', related='pengajuan_tempo_id.dokumen_pengiriman_input', store=True, readonly=False) + dokumen_invoice = fields.Char(string='Dokumen yang dilampirkan saat Pengiriman Invoice', related='pengajuan_tempo_id.dokumen_invoice', store=True, readonly=False) + is_same_address = fields.Boolean(string="Same Address pengiriman invoicr dan alamat pengiriman barang", related='pengajuan_tempo_id.is_same_address', store=True, readonly=False) + is_same_address_street = fields.Boolean(string="Same Address pengiriman barang dan alamat bisnis", related='pengajuan_tempo_id.is_same_address_street', store=True, readonly=False) + + #Referensi + supplier_ids = fields.Many2many('user.pengajuan.tempo.line',related='pengajuan_tempo_id.supplier_ids', string="Suppliers", readonly=False) + + # Dokumen + dokumen_npwp = fields.Many2many( + 'ir.attachment', + 'pengajuan_dokumen_npwp_rel', + string="NPWP Perusahaan", + related='pengajuan_tempo_id.dokumen_npwp', + readonly=False, + tracking=3 + ) + + dokumen_sppkp = fields.Many2many( + 'ir.attachment', + 'pengajuan_dokumen_sppkp_rel', + string="SPPKP Perusahaan", + related='pengajuan_tempo_id.dokumen_sppkp', + readonly=False, + tracking=3 + ) + dokumen_nib = fields.Many2many( + 'ir.attachment', + 'pengajuan_dokumen_nib_rel', + string="NIB", + related='pengajuan_tempo_id.dokumen_nib', + readonly=False, + tracking=3, + track_visibility="onchange" + ) + dokumen_siup = fields.Many2many( + 'ir.attachment', + 'pengajuan_dokumen_siup_rel', + string="SIUP", + related='pengajuan_tempo_id.dokumen_siup', + readonly=False, + tracking=3, + track_visibility="onchange" + ) + + dokumen_tdp = fields.Many2many( + 'ir.attachment', + 'pengajuan_dokumen_tdp_rel', + string="TDP", + related='pengajuan_tempo_id.dokumen_tdp', + readonly=False, + tracking=3, + track_visibility="onchange" + ) + dokumen_skdp = fields.Many2many( + 'ir.attachment', + 'pengajuan_dokumen_skdp_rel', + string="SKDP", + related='pengajuan_tempo_id.dokumen_skdp', + readonly=False, + tracking=3, + track_visibility="onchange" + ) + + dokumen_skt = fields.Many2many( + 'ir.attachment', + 'pengajuan_dokumen_skt_rel', + string="SKT", + related='pengajuan_tempo_id.dokumen_skt', + readonly=False, + tracking=3, + track_visibility="onchange" + ) + + dokumen_akta_perubahan = fields.Many2many( + 'ir.attachment', + 'pengajuan_dokumen_akta_perubahan_rel', + string="Akta Perubahan", + related='pengajuan_tempo_id.dokumen_akta_perubahan', + readonly=False, + tracking=3 + ) + + dokumen_ktp_dirut = fields.Many2many( + 'ir.attachment', + 'pengajuan_dokumen_ktp_dirut_rel', + string="KTP Dirut/Direktur", + related='pengajuan_tempo_id.dokumen_ktp_dirut', + readonly=False, + tracking=3 + ) + + dokumen_akta_pendirian = fields.Many2many( + 'ir.attachment', + 'pengajuan_dokumen_angkta_pendirian_rel', + string="Akta Pendirian", + related='pengajuan_tempo_id.dokumen_akta_pendirian', + readonly=False, + tracking=3 + ) + + dokumen_laporan_keuangan = fields.Many2many( + 'ir.attachment', + 'pengajuan_dokumen_laporan_keuangan_rel', + string="Laporan Keuangan", + related='pengajuan_tempo_id.dokumen_laporan_keuangan', + readonly=False, + tracking=3 + ) + + dokumen_foto_kantor = fields.Many2many( + 'ir.attachment', + 'pengajuan_dokumen_foto_kantor_rel', + string="Foto Kantor (Tampak Depan)", + related='pengajuan_tempo_id.dokumen_foto_kantor', + readonly=False, + tracking=3 + ) + + dokumen_tempat_bekerja = fields.Many2many( + 'ir.attachment', + 'pengajuan_dokumen_tempat_bekerja_rel', + string="Tempat Bekerja", + related='pengajuan_tempo_id.dokumen_tempat_bekerja', + readonly=False, + tracking=3 + ) + + @api.onchange('name_tempo', 'industry_id_tempo', 'street_tempo', 'state_id_tempo', 'city_id_tempo', 'zip_tempo', + 'mobile_tempo', 'bank_name_tempo', 'account_name_tempo', 'account_number_tempo', 'website_tempo', + 'estimasi_tempo', 'tempo_duration_origin', 'tempo_limit_origin', 'category_produk_ids') + def _onchange_related_fields(self): + if self.pengajuan_tempo_id: + # Perbarui nilai di pengajuan_tempo_id + self.pengajuan_tempo_id.name_tempo = self.name_tempo + self.pengajuan_tempo_id.industry_id_tempo = self.industry_id_tempo + self.pengajuan_tempo_id.street_tempo = self.street_tempo + self.pengajuan_tempo_id.state_id_tempo = self.state_id_tempo + self.pengajuan_tempo_id.city_id_tempo = self.city_id_tempo + self.pengajuan_tempo_id.zip_tempo = self.zip_tempo + self.pengajuan_tempo_id.mobile_tempo = self.mobile_tempo + self.pengajuan_tempo_id.bank_name_tempo = self.bank_name_tempo + self.pengajuan_tempo_id.account_name_tempo = self.account_name_tempo + self.pengajuan_tempo_id.account_number_tempo = self.account_number_tempo + self.pengajuan_tempo_id.website_tempo = self.website_tempo + self.pengajuan_tempo_id.portal = self.portal + self.pengajuan_tempo_id.estimasi_tempo = self.estimasi_tempo + self.pengajuan_tempo_id.tempo_duration = self.tempo_duration_origin + self.pengajuan_tempo_id.tempo_limit = self.tempo_limit_origin + self.pengajuan_tempo_id.category_produk_ids = self.category_produk_ids + + @api.onchange('direktur_name', 'direktur_mobile', 'direktur_email', 'purchasing_name', 'purchasing_mobile', + 'purchasing_email', 'finance_name', 'finance_mobile', 'finance_email') + def _onchange_related_fields_kontak(self): + if self.pengajuan_tempo_id: + # Perbarui nilai di pengajuan_tempo_id + self.pengajuan_tempo_id.direktur_name = self.direktur_name + self.pengajuan_tempo_id.direktur_mobile = self.direktur_mobile + self.pengajuan_tempo_id.direktur_email = self.direktur_email + self.pengajuan_tempo_id.purchasing_name = self.purchasing_name + self.pengajuan_tempo_id.purchasing_mobile = self.purchasing_mobile + self.pengajuan_tempo_id.purchasing_email = self.purchasing_email + self.pengajuan_tempo_id.finance_name = self.finance_name + self.pengajuan_tempo_id.finance_mobile = self.finance_mobile + self.pengajuan_tempo_id.finance_email = self.finance_email + + @api.onchange('pic_tittle', 'pic_name', 'street_pengiriman', 'state_id_pengiriman', 'city_id_pengiriman', + 'zip_pengiriman', 'district_id_pengiriman', 'subDistrict_id_pengiriman' + 'invoice_pic_tittle', 'invoice_pic', 'street_invoice', 'state_id_invoice', 'city_id_invoice', + 'district_id_invoice', 'subDistrict_id_invoice', 'zip_invoice', + 'tukar_invoice', 'jadwal_bayar', 'dokumen_pengiriman', 'dokumen_pengiriman_input', 'dokumen_invoice', + 'is_same_address', 'is_same_address_street') + def _onchange_related_fields_pengiriman(self): + if self.pengajuan_tempo_id: + # Perbarui nilai di pengajuan_tempo_id + self.pengajuan_tempo_id.pic_tittle = self.pic_tittle + self.pengajuan_tempo_id.pic_name = self.pic_name + self.pengajuan_tempo_id.street_pengiriman = self.street_pengiriman + self.pengajuan_tempo_id.state_id_pengiriman = self.state_id_pengiriman + self.pengajuan_tempo_id.city_id_pengiriman = self.city_id_pengiriman + self.pengajuan_tempo_id.district_id_pengiriman = self.district_id_pengiriman + self.pengajuan_tempo_id.subDistrict_id_pengiriman = self.subDistrict_id_pengiriman + self.pengajuan_tempo_id.zip_pengiriman = self.zip_pengiriman + self.pengajuan_tempo_id.invoice_pic_tittle = self.invoice_pic_tittle + self.pengajuan_tempo_id.invoice_pic = self.invoice_pic + self.pengajuan_tempo_id.street_invoice = self.street_invoice + self.pengajuan_tempo_id.state_id_invoice = self.state_id_invoice + self.pengajuan_tempo_id.city_id_invoice = self.city_id_invoice + self.pengajuan_tempo_id.district_id_invoice = self.district_id_invoice + self.pengajuan_tempo_id.subDistrict_id_invoice = self.subDistrict_id_invoice + self.pengajuan_tempo_id.zip_invoice = self.zip_invoice + self.pengajuan_tempo_id.tukar_invoice = self.tukar_invoice + self.pengajuan_tempo_id.jadwal_bayar = self.jadwal_bayar + self.pengajuan_tempo_id.dokumen_pengiriman = self.dokumen_pengiriman + self.pengajuan_tempo_id.dokumen_pengiriman_input = self.dokumen_pengiriman_input + self.pengajuan_tempo_id.dokumen_invoice = self.dokumen_invoice + self.pengajuan_tempo_id.is_same_address = self.is_same_address + self.pengajuan_tempo_id.is_same_address_street = self.is_same_address_street + + @api.onchange('supplier_ids') + def _onchange_supplier_ids(self): + if self.pengajuan_tempo_id: + self.pengajuan_tempo_id.supplier_ids = self.supplier_ids + + @api.onchange('dokumen_nib', 'dokumen_npwp', 'dokumen_sppkp', 'dokumen_akta_perubahan', + 'dokumen_ktp_dirut', 'dokumen_akta_pendirian', 'dokumen_laporan_keuangan', + 'dokumen_foto_kantor', 'dokumen_tempat_bekerja', 'dokumen_skdp', 'dokumen_skt', 'dokumen_siup', + 'dokumen_tdp') + def _onchange_related_fields_dokumen(self): + if self.pengajuan_tempo_id: + # Perbarui nilai di pengajuan_tempo_id + self.pengajuan_tempo_id.dokumen_nib = self.dokumen_nib + self.pengajuan_tempo_id.dokumen_siup = self.dokumen_siup + self.pengajuan_tempo_id.dokumen_tdp = self.dokumen_tdp + self.pengajuan_tempo_id.dokumen_skdp = self.dokumen_skdp + self.pengajuan_tempo_id.dokumen_skt = self.dokumen_skt + self.pengajuan_tempo_id.dokumen_npwp = self.dokumen_npwp + self.pengajuan_tempo_id.dokumen_sppkp = self.dokumen_sppkp + self.pengajuan_tempo_id.dokumen_akta_perubahan = self.dokumen_akta_perubahan + self.pengajuan_tempo_id.dokumen_ktp_dirut = self.dokumen_ktp_dirut + self.pengajuan_tempo_id.dokumen_akta_pendirian = self.dokumen_akta_pendirian + self.pengajuan_tempo_id.dokumen_laporan_keuangan = self.dokumen_laporan_keuangan + self.pengajuan_tempo_id.dokumen_foto_kantor = self.dokumen_foto_kantor + self.pengajuan_tempo_id.dokumen_tempat_bekerja = self.dokumen_tempat_bekerja + + @api.onchange('tempo_duration') + def _tempo_duration_change(self, vals): + for tempo in self: + if tempo.env.user.id not in (7, 377, 12182): + raise UserError("Durasi tempo hanya bisa di ubah oleh Sales Manager atau Direktur") + + @api.onchange('tempo_limit') + def _onchange_tempo_limit(self): + for tempo in self: + if tempo.env.user.id not in (7, 377, 12182): + raise UserError("Limit tempo hanya bisa diubah oleh Sales Manager atau Direktur") + def button_approve(self): + for tempo in self: + if not self.tempo_limit: + raise UserError("Limit Tempo harus di isi terlebih dahulu") + if tempo.state_tempo == 'draft': + if tempo.env.user.id in (688, 28, 7): + raise UserError("Pengajuan tempo harus di approve oleh sales manager terlebih dahulu") + else: + if tempo.env.user.id not in (377, 12182): + # if tempo.env.user.id != 12182: + raise UserError("Pengajuan tempo hanya bisa di approve oleh sales manager") + else: + return { + 'type': 'ir.actions.act_window', + 'name': 'Konfirmasi Approve', + 'res_model': 'confirm.approval.wizard', + 'view_mode': 'form', + 'target': 'new', + 'context': { + 'default_tempo_id': tempo.id, + }, + } + + elif tempo.state_tempo == 'approval_sales': + if tempo.env.user.id == 7: + raise UserError("Pengajuan tempo harus di approve oleh Finence terlebih dahulu") + else: + if tempo.env.user.id not in (688, 28, 12182): + # if tempo.env.user.id not in (288,28,12182): + raise UserError("Pengajuan tempo hanya bisa di approve oleh Finence") + else: + return { + 'type': 'ir.actions.act_window', + 'name': 'Konfirmasi Approve', + 'res_model': 'confirm.approval.wizard', + 'view_mode': 'form', + 'target': 'new', + 'context': { + 'default_tempo_id': tempo.id, + }, + } + + elif tempo.state_tempo == 'approval_finance': + if tempo.env.user.id != 7: + # if tempo.env.user.id != 12182: + raise UserError("Pengajuan tempo hanya bisa di approve oleh Direktur") + else: + return { + 'type': 'ir.actions.act_window', + 'name': 'Konfirmasi Approve', + 'res_model': 'confirm.approval.wizard', + 'view_mode': 'form', + 'target': 'new', + 'context': { + 'default_tempo_id': tempo.id, + }, + } + + def button_reject(self): + return { + 'type': 'ir.actions.act_window', + 'name': _('Reject Reason'), + 'res_model': 'reject.reason.wizard', + 'view_mode': 'form', + 'target': 'new', + 'context': {'default_request_id': self.id}, + } + + def write(self, vals): + is_approve = True if self.state_tempo == 'approval_director' or vals.get('state_tempo') == 'approval_director' else False + # if self.is_approve and is_approve: + # raise UserError('Tidak dapat mengubah approval yang sudah diisi') + limit_tempo = '' + if vals.get('tempo_limit'): + limit_tempo = vals.get('tempo_limit') + elif self.tempo_limit: + limit_tempo = self.tempo_limit + else: + limit_tempo = self.pengajuan_tempo_id.tempo_limit + + tempo_duration = '' + if vals.get('tempo_duration'): + tempo_duration = vals.get('tempo_duration') + elif self.tempo_duration: + tempo_duration = self.tempo_duration + else: + tempo_duration = self.pengajuan_tempo_id.tempo_duration + if is_approve: + self.pengajuan_tempo_id.partner_id = self.user_id.id + # informasi perusahaan + self.user_company_id.name_tempo = self.pengajuan_tempo_id.name_tempo + self.user_company_id.industry_id_tempo = self.pengajuan_tempo_id.industry_id_tempo + self.user_company_id.street_tempo = self.pengajuan_tempo_id.street_tempo + self.user_company_id.state_id_tempo = self.pengajuan_tempo_id.state_id_tempo + self.user_company_id.city_id_tempo = self.pengajuan_tempo_id.city_id_tempo + self.user_company_id.zip_tempo = self.pengajuan_tempo_id.zip_tempo + self.user_company_id.mobile_tempo = self.pengajuan_tempo_id.mobile_tempo + self.user_company_id.bank_name_tempo = self.pengajuan_tempo_id.bank_name_tempo + self.user_company_id.account_name_tempo = self.pengajuan_tempo_id.account_name_tempo + self.user_company_id.account_number_tempo = self.pengajuan_tempo_id.account_number_tempo + self.user_company_id.website_tempo = self.pengajuan_tempo_id.website_tempo + self.user_company_id.portal = self.pengajuan_tempo_id.portal + self.user_company_id.estimasi_tempo = self.pengajuan_tempo_id.estimasi_tempo + self.user_company_id.tempo_duration = tempo_duration.id + self.user_company_id.tempo_limit = limit_tempo + self.user_company_id.category_produk_ids = self.pengajuan_tempo_id.category_produk_ids + + # Kontak Perusahaan + self.user_company_id.direktur_name = self.pengajuan_tempo_id.direktur_name + self.user_company_id.direktur_mobile = self.pengajuan_tempo_id.direktur_mobile + self.user_company_id.direktur_email = self.pengajuan_tempo_id.direktur_email + self.user_company_id.purchasing_name = self.pengajuan_tempo_id.purchasing_name + self.user_company_id.purchasing_mobile = self.pengajuan_tempo_id.purchasing_mobile + self.user_company_id.purchasing_email = self.pengajuan_tempo_id.purchasing_email + self.user_company_id.finance_name = self.pengajuan_tempo_id.finance_name + self.user_company_id.finance_mobile = self.pengajuan_tempo_id.finance_mobile + self.user_company_id.finance_email = self.pengajuan_tempo_id.finance_email + + # Data untuk kontak baru + contacts_data = [ + { + "type": "contact", + 'title': 6 if self.pengajuan_tempo_id.direktur_tittle == 'Bpk' else 7, + "name": self.pengajuan_tempo_id.direktur_name, + "email": self.pengajuan_tempo_id.direktur_email, + "phone": self.pengajuan_tempo_id.direktur_mobile, + }, + { + "type": "contact", + 'title': 6 if self.pengajuan_tempo_id.purchasing_tittle == 'Bpk' else 7, + "name": self.pengajuan_tempo_id.purchasing_name, + "email": self.pengajuan_tempo_id.purchasing_email, + "phone": self.pengajuan_tempo_id.purchasing_mobile, + }, + { + "type": "contact", + 'title': 6 if self.pengajuan_tempo_id.finance_tittle == 'Bpk' else 7, + "name": self.pengajuan_tempo_id.finance_name, + "email": self.pengajuan_tempo_id.finance_email, + "phone": self.pengajuan_tempo_id.finance_mobile, + }, + { + "type": "delivery", + "name": self.pengajuan_tempo_id.pic_name, + "street": self.pengajuan_tempo_id.street_pengiriman, + "state_id": self.pengajuan_tempo_id.state_id_pengiriman.id, + "kota_id": self.pengajuan_tempo_id.city_id_pengiriman.id, + "kecamatan_id": self.pengajuan_tempo_id.district_id_pengiriman.id, + "kelurahan_id": self.pengajuan_tempo_id.subDistrict_id_pengiriman.id, + "zip": self.pengajuan_tempo_id.zip_pengiriman, + }, + { + "type": "invoice", + "name": self.pengajuan_tempo_id.invoice_pic, + "street": self.pengajuan_tempo_id.street_invoice, + "state_id": self.pengajuan_tempo_id.state_id_invoice.id, + "kota_id": self.pengajuan_tempo_id.city_id_invoice.id, + "kecamatan_id": self.pengajuan_tempo_id.district_id_invoice.id, + "kelurahan_id": self.pengajuan_tempo_id.subDistrict_id_invoice.id, + "zip": self.pengajuan_tempo_id.zip_invoice, + }, + ] + + # Buat kontak baru untuk company_id + for contact_data in contacts_data: + self.env['res.partner'].create({ + "parent_id": self.user_company_id.id, # Hubungkan ke perusahaan + **contact_data, # Tambahkan data kontak + }) + + # Pengiriman + self.user_company_id.pic_name = self.pengajuan_tempo_id.pic_name + self.user_company_id.street_pengiriman = self.pengajuan_tempo_id.street_pengiriman + self.user_company_id.state_id_pengiriman = self.pengajuan_tempo_id.state_id_pengiriman + self.user_company_id.city_id_pengiriman = self.pengajuan_tempo_id.city_id_pengiriman + self.user_company_id.district_id_pengiriman = self.pengajuan_tempo_id.district_id_pengiriman + self.user_company_id.subDistrict_id_pengiriman = self.pengajuan_tempo_id.subDistrict_id_pengiriman + self.user_company_id.zip_pengiriman = self.pengajuan_tempo_id.zip_pengiriman + self.user_company_id.invoice_pic = self.pengajuan_tempo_id.invoice_pic + self.user_company_id.street_invoice = self.pengajuan_tempo_id.street_invoice + self.user_company_id.state_id_invoice = self.pengajuan_tempo_id.state_id_invoice + self.user_company_id.city_id_invoice = self.pengajuan_tempo_id.city_id_invoice + self.user_company_id.district_id_invoice = self.pengajuan_tempo_id.district_id_invoice + self.user_company_id.subDistrict_id_invoice = self.pengajuan_tempo_id.subDistrict_id_invoice + self.user_company_id.zip_invoice = self.pengajuan_tempo_id.zip_invoice + self.user_company_id.tukar_invoice = self.pengajuan_tempo_id.tukar_invoice + self.user_company_id.jadwal_bayar = self.pengajuan_tempo_id.jadwal_bayar + self.user_company_id.dokumen_pengiriman = self.pengajuan_tempo_id.dokumen_pengiriman + self.user_company_id.dokumen_pengiriman_input = self.pengajuan_tempo_id.dokumen_pengiriman_input + self.user_company_id.dokumen_invoice = self.pengajuan_tempo_id.dokumen_invoice + + # Referensi + self.user_company_id.supplier_ids = self.pengajuan_tempo_id.supplier_ids + + # Dokumen + self.user_company_id.dokumen_npwp = self.pengajuan_tempo_id.dokumen_npwp[0] if self.pengajuan_tempo_id.dokumen_npwp else [] + if self.user_company_id.dokumen_npwp: + self.user_company_id.message_post(body='Dokumen NPWP', attachment_ids=[self.user_company_id.dokumen_npwp.id]) + + self.user_company_id.dokumen_sppkp = self.pengajuan_tempo_id.dokumen_sppkp[0] if self.pengajuan_tempo_id.dokumen_sppkp else [] + if self.user_company_id.dokumen_sppkp: + self.user_company_id.message_post(body='Dokumen SPPKP', attachment_ids=[self.user_company_id.dokumen_sppkp.id]) + + self.user_company_id.dokumen_nib = self.pengajuan_tempo_id.dokumen_nib[0] if self.pengajuan_tempo_id.dokumen_nib else [] + if self.user_company_id.dokumen_nib: + self.user_company_id.message_post(body='Dokumen NIB', attachment_ids=[self.user_company_id.dokumen_nib.id]) + + self.user_company_id.dokumen_siup = self.pengajuan_tempo_id.dokumen_siup[0] if self.pengajuan_tempo_id.dokumen_siup else [] + if self.user_company_id.dokumen_siup: + self.user_company_id.message_post(body='dokumen SIUP', attachment_ids=[self.user_company_id.dokumen_siup.id]) + + self.user_company_id.dokumen_tdp = self.pengajuan_tempo_id.dokumen_tdp[0] if self.pengajuan_tempo_id.dokumen_tdp else [] + if self.user_company_id.dokumen_tdp: + self.user_company_id.message_post(body='dokumen TDP', attachment_ids=[self.user_company_id.dokumen_tdp.id]) + + self.user_company_id.dokumen_skdp = self.pengajuan_tempo_id.dokumen_skdp[0] if self.pengajuan_tempo_id.dokumen_skdp else [] + if self.user_company_id.dokumen_skdp: + self.user_company_id.message_post(body='dokumen SKDP', attachment_ids=[self.user_company_id.dokumen_skdp.id]) + + self.user_company_id.dokumen_skt = self.pengajuan_tempo_id.dokumen_skt[0] if self.pengajuan_tempo_id.dokumen_skt else [] + if self.user_company_id.dokumen_skt: + self.user_company_id.message_post(body='dokumen SKT', attachment_ids=[self.user_company_id.dokumen_skt.id]) + + self.user_company_id.dokumen_akta_perubahan = self.pengajuan_tempo_id.dokumen_akta_perubahan[0] if self.pengajuan_tempo_id.dokumen_akta_perubahan else [] + if self.user_company_id.dokumen_akta_perubahan: + self.user_company_id.message_post(body='Dokumen Akta Perubahan', + attachment_ids=[self.user_company_id.dokumen_akta_perubahan.id]) + + self.user_company_id.dokumen_ktp_dirut = self.pengajuan_tempo_id.dokumen_ktp_dirut[0] if self.pengajuan_tempo_id.dokumen_ktp_dirut else [] + if self.user_company_id.dokumen_ktp_dirut: + self.user_company_id.message_post(body='Dokumen Ktp Dirut', + attachment_ids=[self.user_company_id.dokumen_ktp_dirut.id]) + + self.user_company_id.dokumen_akta_pendirian = self.pengajuan_tempo_id.dokumen_akta_pendirian[0] if self.pengajuan_tempo_id.dokumen_akta_pendirian else [] + if self.user_company_id.dokumen_akta_pendirian: + self.user_company_id.message_post(body='Dokumen Akta Pendirian', + attachment_ids=[self.user_company_id.dokumen_akta_pendirian.id]) + + self.user_company_id.dokumen_laporan_keuangan = self.pengajuan_tempo_id.dokumen_laporan_keuangan[0] if self.pengajuan_tempo_id.dokumen_laporan_keuangan else [] + if self.user_company_id.dokumen_laporan_keuangan: + self.user_company_id.message_post(body='Dokumen Laporan Keuangan', + attachment_ids=[self.user_company_id.dokumen_laporan_keuangan.id]) + + self.user_company_id.dokumen_foto_kantor = self.pengajuan_tempo_id.dokumen_foto_kantor[0] if self.pengajuan_tempo_id.dokumen_foto_kantor else [] + if self.user_company_id.dokumen_foto_kantor: + self.user_company_id.message_post(body='Dokumen Foto Kantor', + attachment_ids=[self.user_company_id.dokumen_foto_kantor.id]) + + self.user_company_id.dokumen_tempat_bekerja = self.pengajuan_tempo_id.dokumen_tempat_bekerja[0] if self.pengajuan_tempo_id.dokumen_tempat_bekerja else [] + if self.user_company_id.dokumen_tempat_bekerja: + self.user_company_id.message_post(body='Dokumen Tempat Bekerja', + attachment_ids=[self.user_company_id.dokumen_tempat_bekerja.id]) + # self.user_company_id.active = True + # user.send_company_request_approve_mail() + self.user_company_id.property_payment_term_id = self.pengajuan_tempo_id.tempo_duration.id + self.user_company_id.active_limit = True + self.user_company_id.warning_stage = float(limit_tempo) - (float(limit_tempo)/2) + self.user_company_id.blocking_stage = limit_tempo + + # Internal Notes + comment = [] + if self.pengajuan_tempo_id.tukar_invoice: + comment.append(f"Jadwal Tukar Invoice: {self.pengajuan_tempo_id.tukar_invoice}") + if self.pengajuan_tempo_id.jadwal_bayar: + comment.append(f"Jadwal Pembayaran: {self.pengajuan_tempo_id.jadwal_bayar}") + self.user_company_id.comment = "\n".join(comment) + + + # template = self.env.ref('indoteknik_custom.mail_template_res_user_company_tempo_approved') + # tempo = self.pengajuan_tempo_id + # template.send_mail(tempo.id, force_send=True) + template = self.env.ref('indoteknik_custom.mail_template_res_user_company_tempo_approved') + template.send_mail(self.id, force_send=True) + # self.user_id.parent_id = new_company.id + # user.send_company_request_reject_mail() + return super(UserPengajuanTempoRequest, self).write(vals) + + def get_user_by_email(self, email): + return request.env['res.users'].search([ + ('login', '=', email), + ('active', 'in', [True, False]) + ]) + + def format_currency(self, number): + number = int(number) + return "{:,}".format(number).replace(',', '.')
\ No newline at end of file diff --git a/indoteknik_custom/models/wati.py b/indoteknik_custom/models/wati.py index f3632334..a0619f83 100644 --- a/indoteknik_custom/models/wati.py +++ b/indoteknik_custom/models/wati.py @@ -32,28 +32,43 @@ class WatiNotification(models.Model): ]).unlink() _logger.info('Success Cleanup WATI Notification') - def _parse_notification(self, limit = 0): + def _parse_notification(self, limit=0): domain = [('is_parsed', '=', False)] notifications = self.search(domain, order='id', limit=limit) notification_not_parsed_count = self.search_count(domain) i = 0 for notification in notifications: i += 1 - _logger.info('[Parse Notification][%s] Process: %s/%s | Not Parsed: %s' % (notification.id, i, str(limit), str(notification_not_parsed_count))) + _logger.info('[Parse Notification][%s] Process: %s/%s | Not Parsed: %s' % + (notification.id, i, str(limit), str(notification_not_parsed_count))) + notification_json = json.loads(notification.json_raw) sender_name = 'Indoteknik' if 'senderName' in notification_json: sender_name = notification_json['senderName'] - ticket_id = notification_json['ticketId'] - date_wati = float(notification_json['timestamp']) - date_wati = datetime.fromtimestamp(date_wati) + ticket_id = notification_json.get('ticketId') + timestamp = notification_json.get('timestamp') + + if not timestamp: + _logger.warning('[Parse Notification][%s] Missing timestamp in notification JSON: %s' % + (notification.id, notification.json_raw)) + continue # Skip this notification + + try: + date_wati = datetime.fromtimestamp(float(timestamp)) + except ValueError as e: + _logger.error('[Parse Notification][%s] Invalid timestamp format: %s. Error: %s' % + (notification.id, timestamp, str(e))) + continue + wati_history = self.env['wati.history'].search([('ticket_id', '=', ticket_id)], limit=1) if wati_history: self._create_wati_history_line(wati_history, ticket_id, sender_name, notification_json, date_wati) else: new_header = self._create_wati_history_header(ticket_id, sender_name, notification_json, date_wati) self._create_wati_history_line(new_header, ticket_id, sender_name, notification_json, date_wati) + notification.is_parsed = True return @@ -217,26 +232,42 @@ class WatiHistory(models.Model): limit = 50 wati_histories = self.env['wati.history'].search(domain, limit=limit) count = 0 + for wati_history in wati_histories: count += 1 - _logger.info('[Parse Notification] Process: %s/%s' % (str(count), str(limit))) + _logger.info('[Parse Notification] Processing: %s/%s', count, limit) wati_api = self.env['wati.api'] - # Perbaikan pada params 'attribute' untuk menghindari masalah "type object is not subscriptable" + # Perbaikan pada parameter JSON params = { 'pageSize': 1, 'pageNumber': 1, - 'attribute': json.dumps([{'name': "phone", 'operator': "contain", 'value': wati_history.wa_id}]), + 'attribute': json.dumps([ + {'name': "phone", 'operator': "contain", 'value': wati_history.wa_id} + ]), } - wati_contacts = wati_api.http_get('/api/v1/getContacts', params) + try: + wati_contacts = wati_api.http_get('/api/v1/getContacts', params) + except Exception as e: + _logger.error('Error while calling WATI API: %s', str(e)) + continue + # Validasi respons dari API + if not isinstance(wati_contacts, dict): + _logger.error('Invalid response format from WATI API: %s', wati_contacts) + continue + if wati_contacts.get('result') != 'success': - return + _logger.warning('WATI API request failed with result: %s', wati_contacts.get('result')) + continue contact_list = wati_contacts.get('contact_list', []) - + if not contact_list: + _logger.info('No contacts found for WA ID: %s', wati_history.wa_id) + continue + perusahaan = email = '' for data in contact_list: custom_params = data.get('customParams', []) @@ -247,12 +278,14 @@ class WatiHistory(models.Model): perusahaan = value elif name == 'email': email = value - # End inner loop # Update wati_history fields - wati_history.perusahaan = perusahaan - wati_history.email = email - wati_history.is_get_attribute = True + wati_history.write({ + 'perusahaan': perusahaan, + 'email': email, + 'is_get_attribute': True, + }) + _logger.info('Wati history updated: %s', wati_history.id) # @api.onchange('last_reply_date') # def _compute_expired_date(self): diff --git a/indoteknik_custom/security/ir.model.access.csv b/indoteknik_custom/security/ir.model.access.csv index dcfee14b..67756cc7 100755 --- a/indoteknik_custom/security/ir.model.access.csv +++ b/indoteknik_custom/security/ir.model.access.csv @@ -44,6 +44,7 @@ access_wati_notification,access.wati.notification,model_wati_notification,,1,1,1 access_wati_api,access.wati.api,model_wati_api,,1,1,1,1 access_wati_contact,access.wati.contact,model_wati_contact,,1,1,1,1 access_user_company_request,access.user.company.request,model_user_company_request,,1,1,1,1 +access_user_pengajuan_tempo_request,access.user.pengajuan.tempo.request,model_user_pengajuan_tempo_request,,1,1,1,1 access_res_partner_company_type,access.res.partner.company_type,model_res_partner_company_type,,1,1,1,1 access_uangmuka_penjualan,access.uangmuka.penjualan,model_uangmuka_penjualan,,1,1,1,1 access_uangmuka_pembelian,access.uangmuka.pembelian,model_uangmuka_pembelian,,1,1,1,1 @@ -149,3 +150,9 @@ access_v_move_outstanding,access.v.move.outstanding,model_v_move_outstanding,,1, access_va_multi_approve,access.va.multi.approve,model_va_multi_approve,,1,1,1,1 access_va_multi_reject,access.va.multi.reject,model_va_multi_reject,,1,1,1,1 access_vendor_sla,access.vendor_sla,model_vendor_sla,,1,1,1,1 +access_stock_immediate_transfer,access.stock.immediate.transfer,model_stock_immediate_transfer,,1,1,1,1 +access_coretax_faktur,access.coretax.faktur,model_coretax_faktur,,1,1,1,1 +access_User_pengajuan_tempo_line,access.user.pengajuan.tempo.line,model_user_pengajuan_tempo_line,,1,1,1,1 +access_user_pengajuan_tempo,access.user.pengajuan.tempo,model_user_pengajuan_tempo,,1,1,1,1 +access_reject_reason_wizard,reject.reason.wizard,model_reject_reason_wizard,,1,1,1,0 +access_confirm_approval_wizard,confirm.approval.wizard,model_confirm_approval_wizard,,1,1,1,0 diff --git a/indoteknik_custom/views/account_move.xml b/indoteknik_custom/views/account_move.xml index 2863af57..4cc35b6d 100644 --- a/indoteknik_custom/views/account_move.xml +++ b/indoteknik_custom/views/account_move.xml @@ -163,5 +163,13 @@ <field name="state">code</field> <field name="code">action = records.open_form_multi_create_reklas_penjualan()</field> </record> + + <record id="action_export_faktur" model="ir.actions.server"> + <field name="name">Export Faktur ke XML</field> + <field name="model_id" ref="account.model_account_move" /> + <field name="binding_model_id" ref="account.model_account_move" /> + <field name="state">code</field> + <field name="code">action = records.export_faktur_to_xml()</field> + </record> </data> </odoo>
\ No newline at end of file diff --git a/indoteknik_custom/views/coretax_faktur.xml b/indoteknik_custom/views/coretax_faktur.xml new file mode 100644 index 00000000..45eea23f --- /dev/null +++ b/indoteknik_custom/views/coretax_faktur.xml @@ -0,0 +1,49 @@ +<?xml version="1.0" encoding="utf-8"?> +<odoo> + <data> + <record id="act_coretax_faktur" model="ir.actions.act_window"> + <field name="name">Export Faktur Pajak Keluaran XML Version</field> + <field name="type">ir.actions.act_window</field> + <field name="res_model">coretax.faktur</field> + <field name="view_mode">form</field> + <field name="target">new</field> + </record> + + <record id="view_coretax_faktur" model="ir.ui.view"> + <field name="name">view coretax faktur</field> + <field name="model">coretax.faktur</field> + <field name="type">form</field> + <field name="arch" type="xml"> + <form string="Export Pajak Keluaran"> + <p> + Klik tombol Export di bawah untuk mulai export Faktur Pajak Keluaran. + Data yang diexport adalah Customer Invoice yang berstatus Open dan belum diexport ke E-Faktur. + </p> + + <p> + Setelah proses export Faktur Pajak Keluaran selesai dilakukan, + download file ini: + </p> + <group> + <field name="export_file" filename="export_filename" readonly="1"/> + </group> + + <p> + Lalu import ke program E-Faktur DJP melalui menu <b>Referensi - Pajak Keluaran - Import</b> + </p> + + <footer> + <button string="Export" name="export_to_download" type="object" class="btn-primary"/> + <button string="Cancel" class="btn-default" special="cancel"/> + </footer> + </form> + </field> + </record> + + <menuitem id="coretax_faktur_export" + parent="vit_efaktur.menu_vit_efaktur_keluaran" + sequence="80" + name="Export FP. Keluaran XML" + action="act_coretax_faktur" /> + </data> +</odoo>
\ No newline at end of file diff --git a/indoteknik_custom/views/product_template.xml b/indoteknik_custom/views/product_template.xml index b6599137..af21984a 100755 --- a/indoteknik_custom/views/product_template.xml +++ b/indoteknik_custom/views/product_template.xml @@ -20,6 +20,7 @@ <field name="unpublished" /> <field name="desc_update_solr" readonly="1" /> <field name="last_update_solr" readonly="1" /> + <!-- <field name="qr_code" widget="image" invisible="1"/> --> </field> <field name="public_categ_ids" position="attributes"> <attribute name="required">0</attribute> @@ -29,6 +30,10 @@ <field name="merchandise_ok"/> <label for="merchandise_ok"/> </div> + <div> + <field name="print_barcode"/> + <label for="print_barcode"/> + </div> </div> <field name="public_categ_ids" position="attributes"> <attribute name="options">{'no_create': True}</attribute> @@ -58,6 +63,7 @@ <field name="arch" type="xml"> <field name="last_update_solr" position="after"> <field name="clean_website_description" /> + <field name="qr_code_variant" widget="image" readonly="True"/> </field> </field> </record> diff --git a/indoteknik_custom/views/purchase_order.xml b/indoteknik_custom/views/purchase_order.xml index 0e6b6792..d22c3b5c 100755 --- a/indoteknik_custom/views/purchase_order.xml +++ b/indoteknik_custom/views/purchase_order.xml @@ -41,6 +41,7 @@ </field> <field name="approval_status" position="after"> <field name="revisi_po"/> + <field name="not_update_purchasepricelist"/> </field> <field name="incoterm_id" position="after"> <field name="amount_total_without_service"/> diff --git a/indoteknik_custom/views/res_partner.xml b/indoteknik_custom/views/res_partner.xml index 1b164161..7e759e31 100644 --- a/indoteknik_custom/views/res_partner.xml +++ b/indoteknik_custom/views/res_partner.xml @@ -75,11 +75,114 @@ <field name="site_id" attrs="{'readonly': [('parent_id', '=', False)]}" domain="[('partner_id', '=', main_parent_id)]" context="{'default_partner_id': active_id}" /> </xpath> <xpath expr="//field[@name='property_payment_term_id']" position="attributes"> - <attribute name="readonly">1</attribute> + <attribute name="readonly">0</attribute> </xpath> <xpath expr="//field[@name='property_supplier_payment_term_id']" position="attributes"> <attribute name="readonly">1</attribute> </xpath> + <notebook> + <page string="Pengajuan Tempo"> + <!-- Informasi Usaha Section --> + <group string="Informasi Usaha" colspan="4"> + <group> + <field name="name_tempo"/> + <field name="industry_id_tempo"/> + <field name="street_tempo"/> + <field name="state_id_tempo"/> + <field name="city_id_tempo"/> + <field name="zip_tempo"/> + <field name="mobile_tempo"/> + <field name="bank_name_tempo"/> + <field name="account_name_tempo"/> + <field name="account_number_tempo"/> + <field name="website_tempo"/> + <field name="portal"/> + <field name="estimasi_tempo"/> + <field name="tempo_duration"/> + <field name="tempo_limit"/> + <field name="category_produk_ids" widget="many2many_tags"/> + </group> + </group> + + <!-- Kontak Perusahaan Section --> + <group string="Kontak Perusahaan" colspan="4"> + <group> + <field name="direktur_name"/> + <field name="direktur_mobile"/> + <field name="direktur_email"/> + </group> + <group> + <field name="purchasing_name"/> + <field name="purchasing_mobile"/> + <field name="purchasing_email"/> + </group> + <group> + <field name="finance_name"/> + <field name="finance_mobile"/> + <field name="finance_email"/> + </group> + </group> + + <!-- Pengiriman Section --> + <group string="Pengiriman" colspan="4"> + <group> + <field name="pic_name"/> + <field name="street_pengiriman"/> + <field name="state_id_pengiriman"/> + <field name="city_id_pengiriman"/> + <field name="district_id_pengiriman"/> + <field name="subDistrict_id_pengiriman"/> + <field name="zip_pengiriman"/> + </group> + <group> + <field name="invoice_pic"/> + <field name="street_invoice"/> + <field name="state_id_invoice"/> + <field name="city_id_invoice"/> + <field name="district_id_invoice"/> + <field name="subDistrict_id_invoice"/> + <field name="zip_invoice"/> + </group> + <group> + <field name="tukar_invoice"/> + <field name="jadwal_bayar"/> + <field name="dokumen_pengiriman"/> + <field name="dokumen_pengiriman_input"/> + <field name="dokumen_invoice"/> + </group> + </group> + + <!-- Supplier Lines Section --> + <group string="Suppliers"> + <field name="supplier_ids"> + <tree> + <field name="name_supplier"/> + <field name="pic_name"/> + <field name="phone"/> + <field name="tempo_duration"/> + <field name="credit_limit"/> + </tree> + </field> + </group> + + <group string="Dokumen"> + <field name="dokumen_npwp" /> + <field name="dokumen_sppkp" /> + <field name="dokumen_nib" /> + <field name="dokumen_siup" /> + <field name="dokumen_tdp" /> + <field name="dokumen_skdp" /> + <field name="dokumen_skt"/> + <field name="dokumen_akta_pendirian" /> + <field name="dokumen_akta_perubahan" /> + <field name="dokumen_tempat_bekerja" /> + <field name="dokumen_foto_kantor" /> + <field name="dokumen_ktp_dirut" /> + <field name="dokumen_laporan_keuangan" /> + <field name="dokumen_ktp_dirut" /> + </group> + </page> + </notebook> </field> </record> </data> diff --git a/indoteknik_custom/views/res_users.xml b/indoteknik_custom/views/res_users.xml index 39b9d43e..d7a6b2dd 100644 --- a/indoteknik_custom/views/res_users.xml +++ b/indoteknik_custom/views/res_users.xml @@ -254,5 +254,7 @@ </table> </field> </record> + + </data> </odoo>
\ No newline at end of file diff --git a/indoteknik_custom/views/sale_order.xml b/indoteknik_custom/views/sale_order.xml index 703b4d49..3539dbf3 100755 --- a/indoteknik_custom/views/sale_order.xml +++ b/indoteknik_custom/views/sale_order.xml @@ -107,6 +107,14 @@ {'readonly': [('state', 'in', ('done','cancel'))]} </attribute> </xpath> + <xpath expr="//form/sheet/notebook/page/field[@name='order_line']/tree" position="inside"> + <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"> + {'readonly': [('desc_updatable', '=', False)]} + </attribute> + </xpath> <xpath expr="//form/sheet/notebook/page/field[@name='order_line']/tree/field[@name='price_unit']" position="attributes"> <attribute name="attrs"> { diff --git a/indoteknik_custom/views/stock_picking.xml b/indoteknik_custom/views/stock_picking.xml index 562be8d9..8acba608 100644 --- a/indoteknik_custom/views/stock_picking.xml +++ b/indoteknik_custom/views/stock_picking.xml @@ -61,10 +61,17 @@ type="object" attrs="{'invisible': [('carrier_id', '!=', 151)]}" /> + <button name="action_fetch_lalamove_order" + string="Tracking Lalamove" + type="object" + attrs="{'invisible': [('carrier_id', '!=', 9)]}" + /> </button> <field name="backorder_id" position="after"> <field name="summary_qty_detail"/> <field name="count_line_detail"/> + <field name="dokumen_tanda_terima"/> + <field name="dokumen_pengiriman"/> </field> <field name="weight_uom_name" position="after"> <group> @@ -79,6 +86,9 @@ <field name="partner_id" position="after"> <field name="real_shipping_id"/> </field> + <field name="product_uom_qty" position="attributes"> + <attribute name="attrs">{'readonly': [('parent.picking_type_code', '=', 'incoming')]}</attribute> + </field> <field name="date_done" position="after"> <field name="arrival_time"/> </field> @@ -120,6 +130,8 @@ </field> <field name="product_uom" position="after"> <field name="sale_id" attrs="{'readonly': 1}" optional="hide"/> + <field name="print_barcode" optional="hide"/> + <field name="qr_code_variant" widget="image" optional="hide"/> </field> <page name="note" position="after"> <page string="E-Faktur" name="efaktur" attrs="{'invisible': [['is_internal_use', '=', False]]}"> @@ -148,7 +160,7 @@ <field name="sj_documentation" widget="image" /> <field name="paket_documentation" widget="image" /> </group> - <group> + <group attrs="{'invisible': [('carrier_id', '!=', 151)]}"> <field name="envio_id" invisible="1"/> <field name="envio_code"/> <field name="envio_ref_code"/> @@ -166,13 +178,39 @@ <field name="envio_latest_longitude" invisible="1"/> <field name="tracking_by" invisible="1"/> </group> + <group attrs="{'invisible': [('carrier_id', '!=', 9)]}"> + <field name="lalamove_data" invisible="1"/> + <field name="lalamove_order_id"/> + <field name="lalamove_address"/> + <field name="lalamove_name"/> + <field name="lalamove_phone"/> + <field name="lalamove_status"/> + <field name="lalamove_delivered_at"/> + <field name="lalamove_image_url" invisible="1"/> + <field name="lalamove_image_html"/> + </group> </group> </page> + <!-- <page string="Check Product" name="check_product"> + <field name="check_product_lines"/> + </page> --> </page> </field> </record> + <!-- <record id="check_product_tree" model="ir.ui.view"> + <field name="name">check.product.tree</field> + <field name="model">check.product</field> + <field name="arch" type="xml"> + <tree editable="bottom" decoration-warning="status == 'Pending'" decoration-success="status == 'Done'"> + <field name="product_id"/> + <field name="quantity"/> + <field name="status"/> + </tree> + </field> + </record> --> + <record id="view_stock_move_line_detailed_operation_tree_inherit" model="ir.ui.view"> <field name="name">stock.move.line.operations.tree.inherit</field> <field name="model">stock.move.line</field> diff --git a/indoteknik_custom/views/user_company_request.xml b/indoteknik_custom/views/user_company_request.xml index 1c80e923..6d5642e6 100644 --- a/indoteknik_custom/views/user_company_request.xml +++ b/indoteknik_custom/views/user_company_request.xml @@ -54,12 +54,16 @@ <field name="res_model">user.company.request</field> <field name="view_mode">tree,form</field> </record> + <menuitem id="res_partner_menu_user" + name="User Request" + parent="contacts.menu_contacts" + groups="base.group_system" + sequence="3"/> - <menuitem - id="menu_user_company_request" - name="User Company Request" - parent="contacts.menu_contacts" - sequence="3" - action="action_user_company_request" - /> +<menuitem id="menu_user_company_request" + name="User Company Request" + parent="res_partner_menu_user" + sequence="4" + action="action_user_company_request" + groups="base.group_system"/> </odoo>
\ No newline at end of file diff --git a/indoteknik_custom/views/user_pengajuan_tempo.xml b/indoteknik_custom/views/user_pengajuan_tempo.xml new file mode 100644 index 00000000..f9e747b3 --- /dev/null +++ b/indoteknik_custom/views/user_pengajuan_tempo.xml @@ -0,0 +1,344 @@ +<odoo> + <!-- Form view for userPengajuanTempo --> + <record id="view_user_pengajuan_tempo_form" model="ir.ui.view"> + <field name="name">user.pengajuan.tempo.form</field> + <field name="model">user.pengajuan.tempo</field> + <field name="arch" type="xml"> + <form string="Pengajuan Tempo"> + <sheet> + <!-- Informasi Usaha Section --> + <group string="Informasi Usaha" colspan="4"> + <group> + <field name="name_tempo"/> + <field name="industry_id_tempo"/> + <field name="street_tempo"/> + <field name="state_id_tempo"/> + <field name="city_id_tempo"/> + <field name="district_id_tempo"/> + <field name="subDistrict_id_tempo"/> + <field name="zip_tempo"/> + <field name="mobile_tempo"/> + <field name="bank_name_tempo"/> + <field name="account_name_tempo"/> + <field name="account_number_tempo"/> + <field name="website_tempo"/> + <field name="portal"/> + <field name="estimasi_tempo"/> + <field name="tempo_duration"/> + <field name="tempo_limit"/> + <field name="category_produk_ids" widget="many2many_tags"/> + </group> + </group> + + <!-- Kontak Perusahaan Section --> + <group string="Kontak Perusahaan" colspan="4"> + <group> + <field name="direktur_name"/> + <field name="direktur_mobile"/> + <field name="direktur_email"/> + </group> + <group> + <field name="purchasing_name"/> + <field name="purchasing_mobile"/> + <field name="purchasing_email"/> + </group> + <group> + <field name="finance_name"/> + <field name="finance_mobile"/> + <field name="finance_email"/> + </group> + </group> + + <!-- Pengiriman Section --> + <group string="Pengiriman" colspan="4"> + <group> + <field name="pic_name"/> + <field name="street_pengiriman"/> + <field name="state_id_pengiriman"/> + <field name="city_id_pengiriman"/> + <field name="district_id_pengiriman"/> + <field name="subDistrict_id_pengiriman"/> + <field name="zip_pengiriman"/> + </group> + <group> + <field name="invoice_pic"/> + <field name="street_invoice"/> + <field name="state_id_invoice"/> + <field name="city_id_invoice"/> + <field name="district_id_invoice"/> + <field name="subDistrict_id_invoice"/> + <field name="zip_invoice"/> + </group> + <group> + <field name="tukar_invoice"/> + <field name="jadwal_bayar"/> + <field name="dokumen_pengiriman"/> + <field name="dokumen_pengiriman_input"/> + <field name="dokumen_invoice"/> + </group> + </group> + + <!-- Supplier Lines Section --> + <group string="Suppliers"> + <field name="supplier_ids"> + <tree> + <field name="name_supplier"/> + <field name="pic_name"/> + <field name="phone"/> + <field name="tempo_duration"/> + <field name="credit_limit"/> + </tree> + </field> + </group> + + <group string="Dokumen"> + <field name="dokumen_npwp" widget="many2many_binary" /> + <field name="dokumen_sppkp" widget="many2many_binary" /> + <field name="dokumen_nib" widget="many2many_binary" options="{'no_create': True, 'no_open': False}"/> + <field name="dokumen_siup" widget="many2many_binary" options="{'no_create': True, 'no_open': False}"/> + <field name="dokumen_tdp" widget="many2many_binary" options="{'no_create': True, 'no_open': False}"/> + <field name="dokumen_skdp" widget="many2many_binary" options="{'no_create': True, 'no_open': False}"/> + <field name="dokumen_skt" widget="many2many_binary" options="{'no_create': True, 'no_open': False}"/> + <field name="dokumen_akta_pendirian" widget="many2many_binary" options="{'no_create': True, 'no_open': False}"/> + <field name="dokumen_akta_perubahan" widget="many2many_binary" /> + <field name="dokumen_tempat_bekerja" widget="many2many_binary" options="{'no_create': True, 'no_open': False}"/> + <field name="dokumen_foto_kantor" widget="many2many_binary" options="{'no_create': True, 'no_open': False}"/> + <field name="dokumen_ktp_dirut" widget="many2many_binary" options="{'no_create': True, 'no_open': False}"/> + <field name="dokumen_laporan_keuangan" widget="many2many_binary" options="{'no_create': True, 'no_open': False}"/> + <field name="dokumen_ktp_dirut" widget="many2many_binary" options="{'no_create': True, 'no_open': False}"/> + </group> + </sheet> + <div class="oe_chatter"> + <field name="message_ids" widget="mail_thread"/> + </div> + </form> + </field> + </record> + + <!-- Tree view for userPengajuanTempo --> + <record id="view_user_pengajuan_tempo_tree" model="ir.ui.view"> + <field name="name">user.pengajuan.tempo.tree</field> + <field name="model">user.pengajuan.tempo</field> + <field name="arch" type="xml"> + <tree string="Pengajuan Tempo"> + <field name="name_tempo"/> + <field name="industry_id_tempo"/> + <field name="tempo_limit"/> + <field name="estimasi_tempo"/> + </tree> + </field> + </record> + + <record id="mail_template_res_user_company_request_tempo_review" model="mail.template"> + <field name="name">Users: Company Request Tempo Review</field> + <field name="model_id" ref="indoteknik_custom.model_user_pengajuan_tempo"/> + <field name="subject">Permohonan Tempo Anda Sedang Ditinjau</field> + <field name="email_from">"Indoteknik.com" <noreply@indoteknik.com></field> + <field name="reply_to">sales@indoteknik.com</field> + <field name="email_to">${object.user_id.login | safe}</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;"> + <tr><td align="center"> + <table border="0" cellpadding="0" cellspacing="0" width="590" style="font-size: 13px; padding: 16px; background-color: white; color: #454748; border-collapse:separate;"> + <!-- HEADER --> + <tbody> + <tr> + <td align="center" style="min-width: 590px;"> + <table border="0" cellpadding="0" cellspacing="0" width="590" style="min-width: 590px; background-color: white; padding: 0px 8px 0px 8px; border-collapse:separate;"> + <tr> + <td valign="middle"> + <span></span> + </td> + </tr> + + <tr> + <td colspan="2" style="text-align:center;"> + <hr width="100%" style="background-color:rgb(204,204,204);border:medium none;clear:both;display:block;font-size:0px;min-height:1px;line-height:0; margin: 16px 0px 16px 0px;" /> + </td> + </tr> + </table> + </td> + </tr> + <!-- CONTENT --> + <tr> + <td align="center" style="min-width: 590px;"> + <table border="0" cellpadding="0" cellspacing="0" width="590" style="min-width: 590px; background-color: white; padding: 0px 8px 0px 8px; border-collapse:separate;"> + <tr><td style="padding-bottom: 24px;"><b>Hai. ${object.name_tempo.name},</b></td></tr> + + <tr><td style="padding-bottom: 16px;">Terima kasih atas kepercayaan Anda memilih indoteknik.com. Kami telah menerima permohonan pembayaran tempo Anda.</td></tr> + <tr><td style="padding-bottom: 16px;">Saat ini, tim kami sedang melakukan peninjauan terhadap permohonan Anda. Proses peninjauan ini membutuhkan waktu.</td></tr> + <tr> + <td style="padding-bottom: 16px; ">Kami akan informasikan kembali mengenai hasil peninjauan pembayaran tempo anda melalui email ini.</td> + </tr> + + + <tr><td style="padding-bottom: 2px;"><b>Hormat kami,</b></td></tr> + <tr><td style="padding-bottom: 2px;">PT. INDOTEKNIK DOTCOM GEMILANG</td></tr> + <tr> + <td valign="middle" align="left"> + <img src="https://erp.indoteknik.com/api/image/ir.attachment/datas/2135765" alt="Indoteknik" style="max-width: 50%; height: auto;"></img> + </td> + </tr> + <tr> + <td style="text-align:center;"> + <hr width="100%" + style="background-color:rgb(204,204,204);border:medium none;clear:both;display:block;font-size:0px;min-height:1px;line-height:0; margin: 16px 0px 16px 0px;" /> + </td> + </tr> + </table> + </td> + </tr> + <!-- CONTENT --> + </tbody> + </table> + </td></tr> + </table> + </field> + </record> + + <record id="mail_template_res_user_company_new_tempo_to_sales" model="mail.template"> + <field name="name">Users: Company New Tempo To Sales</field> + <field name="model_id" ref="indoteknik_custom.model_user_pengajuan_tempo"/> + <field name="subject">Pengajuan Tempo Harus di Periksa!</field> + <field name="email_from">"Indoteknik.com" <noreply@indoteknik.com></field> + <field name="reply_to">sales@indoteknik.com</field> + <field name="email_to">vita@indoteknik.co.id</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;"> + <tr><td align="center"> + <table border="0" cellpadding="0" cellspacing="0" width="590" style="font-size: 13px; padding: 16px; background-color: white; color: #454748; border-collapse:separate;"> + <!-- HEADER --> + <tbody> + <tr> + <td align="center" style="min-width: 590px;"> + <table border="0" cellpadding="0" cellspacing="0" width="590" style="min-width: 590px; background-color: white; padding: 0px 8px 0px 8px; border-collapse:separate;"> + <tr> + <td valign="middle"> + <span></span> + </td> + </tr> + + <tr> + <td colspan="2" style="text-align:center;"> + <hr width="100%" style="background-color:rgb(204,204,204);border:medium none;clear:both;display:block;font-size:0px;min-height:1px;line-height:0; margin: 16px 0px 16px 0px;" /> + </td> + </tr> + </table> + </td> + </tr> + <!-- CONTENT --> + <tr> + <td align="center" style="min-width: 590px;"> + <table border="0" cellpadding="0" cellspacing="0" width="590" style="min-width: 590px; background-color: white; padding: 0px 8px 0px 8px; border-collapse:separate;"> + <tr><td style="padding-bottom: 24px;"><b>Halo Manager Tim Sales, Novita Mayasari.</b></td></tr> + + <tr><td style="padding-bottom: 16px;">Kami sampaikan informasi bahwa saat ini terdapat pengajuan Pembayaran Tempo dari ${object.name_tempo.name} melalui website Indoteknik.com.</td></tr> + + <tr><td style="padding-bottom: 16px;">Mohon dapat segera melakukan pengecekan dan evaluasi terhadap data perusahaan yang telah dilampirkan tersebut agar proses pengajuan dapat diproses lebih lanjut.</td></tr> + + + <tr><td style="padding-bottom: 16px;">Terima kasih atas perhatian dan kerjasamanya.</td></tr> + + <tr><td style="padding-bottom: 2px;"><b>Hormat kami,</b></td></tr> + <tr><td style="padding-bottom: 2px;">PT. INDOTEKNIK DOTCOM GEMILANG</td></tr> + <tr> + <td valign="middle" align="left"> + <img src="https://erp.indoteknik.com/api/image/ir.attachment/datas/2135765" alt="Indoteknik" style="max-width: 50%; height: auto;"></img> + </td> + </tr> + <tr> + <td style="text-align:center;"> + <hr width="100%" + style="background-color:rgb(204,204,204);border:medium none;clear:both;display:block;font-size:0px;min-height:1px;line-height:0; margin: 16px 0px 16px 0px;" /> + </td> + </tr> + </table> + </td> + </tr> + <!-- CONTENT --> + </tbody> + </table> + </td></tr> + </table> + </field> + </record> + <record id="mail_template_res_user_company_tempo_approved_by_sales" model="mail.template"> + <field name="name">Users: Company Tempo Approved By Sales</field> + <field name="model_id" ref="indoteknik_custom.model_user_pengajuan_tempo_request"/> + <field name="subject">Pengajuan Tempo Harus di Periksa!</field> + <field name="email_from">"Indoteknik.com" <noreply@indoteknik.com></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">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;"> + <tr><td align="center"> + <table border="0" cellpadding="0" cellspacing="0" width="590" style="font-size: 13px; padding: 16px; background-color: white; color: #454748; border-collapse:separate;"> + <!-- HEADER --> + <tbody> + <tr> + <td align="center" style="min-width: 590px;"> + <table border="0" cellpadding="0" cellspacing="0" width="590" style="min-width: 590px; background-color: white; padding: 0px 8px 0px 8px; border-collapse:separate;"> + <tr> + <td valign="middle"> + <span></span> + </td> + </tr> + + <tr> + <td colspan="2" style="text-align:center;"> + <hr width="100%" style="background-color:rgb(204,204,204);border:medium none;clear:both;display:block;font-size:0px;min-height:1px;line-height:0; margin: 16px 0px 16px 0px;" /> + </td> + </tr> + </table> + </td> + </tr> + <!-- CONTENT --> + <tr> + <td align="center" style="min-width: 590px;"> + <table border="0" cellpadding="0" cellspacing="0" width="590" style="min-width: 590px; background-color: white; padding: 0px 8px 0px 8px; border-collapse:separate;"> + <tr><td style="padding-bottom: 24px;"><b>Halo Tim Finance Indoteknik,</b></td></tr> + + <tr><td style="padding-bottom: 16px;">Kami informasikan bahwa pengajuan tempo dari ${object.pengajuan_tempo_id.name_tempo.name} telah disetujui oleh Manager Divisi Sales.</td></tr> + + <tr><td style="padding-bottom: 16px;">Untuk kelancaran proses selanjutnya, kami mohon kesediaannya untuk melakukan pengecekan ulang terhadap pengajuan tempo tersebut.</td></tr> + + + <tr><td style="padding-bottom: 16px;">Terima kasih atas perhatian dan kerjasamanya.</td></tr> + + <tr><td style="padding-bottom: 2px;"><b>Hormat kami,</b></td></tr> + <tr><td style="padding-bottom: 2px;">PT. INDOTEKNIK DOTCOM GEMILANG</td></tr> + <tr> + <td valign="middle" align="left"> + <img src="https://erp.indoteknik.com/api/image/ir.attachment/datas/2135765" alt="Indoteknik" style="max-width: 50%; height: auto;"></img> + </td> + </tr> + <tr> + <td style="text-align:center;"> + <hr width="100%" + style="background-color:rgb(204,204,204);border:medium none;clear:both;display:block;font-size:0px;min-height:1px;line-height:0; margin: 16px 0px 16px 0px;" /> + </td> + </tr> + </table> + </td> + </tr> + <!-- CONTENT --> + </tbody> + </table> + </td></tr> + </table> + </field> + </record> + + <!-- Action to open form and tree views --> + <record id="action_user_pengajuan_tempo" model="ir.actions.act_window"> + <field name="name">Pengajuan Tempo</field> + <field name="res_model">user.pengajuan.tempo</field> + <field name="view_mode">tree,form</field> + </record> + + <!-- Menu item to access Pengajuan Tempo --> + <menuitem id="menu_user_pengajuan_tempo_root" name="Pengajuan Tempo" /> + <menuitem id="menu_user_pengajuan_tempo" name="Pengajuan Tempo Records" parent="menu_user_pengajuan_tempo_root" action="action_user_pengajuan_tempo"/> +</odoo> diff --git a/indoteknik_custom/views/user_pengajuan_tempo_line.xml b/indoteknik_custom/views/user_pengajuan_tempo_line.xml new file mode 100644 index 00000000..60b510bc --- /dev/null +++ b/indoteknik_custom/views/user_pengajuan_tempo_line.xml @@ -0,0 +1,42 @@ +<odoo> + <record id="view_user_pengajuan_tempo_line_tree" model="ir.ui.view"> + <field name="name">user_pengajuan.tempo.line.tree</field> + <field name="model">user_pengajuan.tempo.line</field> + <field name="arch" type="xml"> + <tree string="Pengajuan Tempo Lines"> + <field name="name_supplier" string="Nama Supplier"/> + <field name="pic_name" string="PIC"/> + <field name="phone" string="Telepon"/> + <field name="tempo_duration" string="Durasi Tempo"/> + <field name="credit_limit" string="Credit Limit"/> + </tree> + </field> + </record> + + <record id="view_user_pengajuan_tempo_line_form" model="ir.ui.view"> + <field name="name">pengajuan.tempo.line.form</field> + <field name="model">pengajuan.tempo.line</field> + <field name="arch" type="xml"> + <form string="Pengajuan Tempo Line"> + <group> + <field name="name_supplier"/> + <field name="pic_name"/> + <field name="phone"/> + <field name="tempo_duration"/> + <field name="credit_limit"/> + </group> + </form> + </field> + </record> + + <!-- Action to open the list view --> + <record id="action_user_pengajuan_tempo_line" model="ir.actions.act_window"> + <field name="name">Pengajuan Tempo Lines</field> + <field name="res_model">pengajuan.tempo.line</field> + <field name="view_mode">tree,form</field> + </record> + + <!-- Add a menu item to access the list view --> + <menuitem id="menu_user_pengajuan_tempo_line_root" name="Pengajuan Tempo" /> + <menuitem id="menu_user_pengajuan_tempo_line" name="Pengajuan Tempo Lines" parent="menu_user_pengajuan_tempo_line_root" action="action_user_pengajuan_tempo_line"/> +</odoo> diff --git a/indoteknik_custom/views/user_pengajuan_tempo_request.xml b/indoteknik_custom/views/user_pengajuan_tempo_request.xml new file mode 100644 index 00000000..bb8262c9 --- /dev/null +++ b/indoteknik_custom/views/user_pengajuan_tempo_request.xml @@ -0,0 +1,416 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<odoo> + <record id="user_pengajuan_tempo_request_tree" model="ir.ui.view"> + <field name="name">user.pengajuan.tempo.request.tree</field> + <field name="model">user.pengajuan.tempo.request</field> + <field name="arch" type="xml"> + <tree create="1" default_order="create_date desc"> + <field name="user_id"/> + <field name="pengajuan_tempo_id"/> + <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"/> + </tree> + </field> + </record> + + <record id="user_pengajuan_tempo_request_form" model="ir.ui.view"> + <field name="name">user.pengajuan.tempo.request.form</field> + <field name="model">user.pengajuan.tempo.request</field> + <field name="arch" type="xml"> + <form create="0"> + <header> + <button name="button_approve" + string="Approve Tempo" + attrs="{'invisible': [('state_tempo', 'in', ['approval_director','reject'])]}" + type="object" + class="oe_highlight"/> + <button name="button_reject" + string="Reject" + attrs="{'invisible': [('state_tempo', 'in', ['approval_director','reject'])]}" + type="object" + groups="purchase.group_purchase_manager" + class="oe_highlight"/> + <field name="state_tempo" widget="statusbar" + statusbar_visible="draft,approval_sales,approval_finance,approval_director" + statusbar_colors='{"reject":"red"}'/> + </header> + <sheet> + <group> + <group> + <field name="user_id" readonly="1"/> + <field name="pengajuan_tempo_id"/> + <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'}"/> + </group> + </group> + <notebook> + <page string="Informasi Usaha"> + <!-- Informasi Usaha Section --> + <group> + <field name="name_tempo" /> + <field name="industry_id_tempo" /> + <field name="street_tempo" /> + <field name="state_id_tempo" /> + <field name="city_id_tempo" /> + <field name="zip_tempo" /> + <field name="mobile_tempo" /> + <field name="bank_name_tempo" /> + <field name="account_name_tempo" /> + <field name="account_number_tempo" /> + <field name="website_tempo" /> + <field name="estimasi_tempo" /> + <field name="tempo_duration_origin" /> + <field name="tempo_limit_origin" /> +<!-- <field name="category_produk_ids" widget="many2many_tags" />--> + </group> + </page> + <page string="Kontak Perusahaan"> + <group> + <field name="direktur_name"/> + <field name="direktur_mobile"/> + <field name="direktur_email"/> + </group> + <group> + <field name="purchasing_name"/> + <field name="purchasing_mobile"/> + <field name="purchasing_email"/> + </group> + <group> + <field name="finance_name"/> + <field name="finance_mobile"/> + <field name="finance_email"/> + </group> + </page> + <Page string="Pengiriman"> + <group> + <field name="pic_name"/> + <field name="street_pengiriman"/> + <field name="state_id_pengiriman"/> + <field name="city_id_pengiriman"/> + <field name="district_id_pengiriman"/> + <field name="subDistrict_id_pengiriman"/> + <field name="zip_pengiriman"/> + </group> + <group> + <field name="invoice_pic"/> + <field name="street_invoice"/> + <field name="state_id_invoice"/> + <field name="city_id_invoice"/> + <field name="district_id_invoice"/> + <field name="subDistrict_id_invoice"/> + <field name="zip_invoice"/> + </group> + <group> + <field name="tukar_invoice"/> + <field name="jadwal_bayar"/> + <field name="dokumen_pengiriman"/> + <field name="dokumen_pengiriman_input"/> + <field name="dokumen_invoice"/> + </group> + </Page> + <Page string="Suppliers"> + <field name="supplier_ids"> + <tree> + <field name="name_supplier"/> + <field name="pic_name"/> + <field name="phone"/> + <field name="tempo_duration"/> + <field name="credit_limit"/> + </tree> + </field> + </Page> + <Page string="Dokumen"> + <group > + <field name="dokumen_npwp" widget="many2many_binary" options="{'no_create': True, 'no_open': False}"/> + <field name="dokumen_sppkp" widget="many2many_binary" options="{'no_create': True, 'no_open': False}"/> + <field name="dokumen_nib" widget="many2many_binary" options="{'no_create': True, 'no_open': False}"/> + <field name="dokumen_siup" widget="many2many_binary" options="{'no_create': True, 'no_open': False}"/> + <field name="dokumen_tdp" widget="many2many_binary" options="{'no_create': True, 'no_open': False}"/> + <field name="dokumen_skdp" widget="many2many_binary" options="{'no_create': True, 'no_open': False}"/> + <field name="dokumen_skt" widget="many2many_binary" options="{'no_create': True, 'no_open': False}"/> + <field name="dokumen_akta_pendirian" widget="many2many_binary" options="{'no_create': True, 'no_open': False}"/> + <field name="dokumen_akta_perubahan" widget="many2many_binary" options="{'no_create': True, 'no_open': False}"/> + <field name="dokumen_tempat_bekerja" widget="many2many_binary" options="{'no_create': True, 'no_open': False}"/> + <field name="dokumen_foto_kantor" widget="many2many_binary" options="{'no_create': True, 'no_open': False}"/> + <field name="dokumen_ktp_dirut" widget="many2many_binary" options="{'no_create': True, 'no_open': False}"/> + <field name="dokumen_laporan_keuangan" widget="many2many_binary" options="{'no_create': True, 'no_open': False}"/> + <field name="dokumen_ktp_dirut" widget="many2many_binary" options="{'no_create': True, 'no_open': False}"/> + </group> + </Page> + </notebook> + </sheet> + <div class="oe_chatter"> + <field name="message_ids" widget="mail_thread"/> + </div> + </form> + </field> +</record> + + + + + <!-- Wizard for Reject Reason --> +<record id="view_reject_reason_wizard_form" model="ir.ui.view"> + <field name="name">reject.reason.wizard.form</field> + <field name="model">reject.reason.wizard</field> + <field name="arch" type="xml"> + <form string="Reject Reason"> + <group> + <field name="reason_reject" widget="text"/> + </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_reject_reason_wizard" model="ir.actions.act_window"> + <field name="name">Reject Reason</field> + <field name="res_model">reject.reason.wizard</field> + <field name="view_mode">form</field> + <field name="target">new</field> +</record> + + +<record id="view_confirm_approval_wizard_form" model="ir.ui.view"> + <field name="name">confirm.approval.wizard.form</field> + <field name="model">confirm.approval.wizard</field> + <field name="arch" type="xml"> + <form string="Konfirmasi Approval"> + <group> + <p>Apakah Anda yakin ingin mengapprove tempo ini?</p> + </group> + <footer> + <button string="Batal" class="btn-secondary" special="cancel"/> + <button string="Konfirmasi" type="object" name="confirm_approval" class="btn-primary"/> + </footer> + </form> + </field> +</record> + + <record id="mail_template_res_user_company_tempo_to_aprove_director" model="mail.template"> + <field name="name">Users: Company Tempo To Approve Director</field> + <field name="model_id" ref="indoteknik_custom.model_user_pengajuan_tempo_request"/> + <field name="subject">Pengajuan Tempo Harus di Periksa!</field> + <field name="email_from">"Indoteknik.com" <noreply@indoteknik.com></field> + <field name="reply_to">sales@indoteknik.com</field> + <field name="email_to">akbar@fixcomart.co.id</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;"> + <tr><td align="center"> + <table border="0" cellpadding="0" cellspacing="0" width="590" style="font-size: 13px; padding: 16px; background-color: white; color: #454748; border-collapse:separate;"> + <!-- HEADER --> + <tbody> + <tr> + <td align="center" style="min-width: 590px;"> + <table border="0" cellpadding="0" cellspacing="0" width="590" style="min-width: 590px; background-color: white; padding: 0px 8px 0px 8px; border-collapse:separate;"> + <tr> + <td valign="middle"> + <span></span> + </td> + </tr> + + <tr> + <td colspan="2" style="text-align:center;"> + <hr width="100%" style="background-color:rgb(204,204,204);border:medium none;clear:both;display:block;font-size:0px;min-height:1px;line-height:0; margin: 16px 0px 16px 0px;" /> + </td> + </tr> + </table> + </td> + </tr> + <!-- CONTENT --> + <tr> + <td align="center" style="min-width: 590px;"> + <table border="0" cellpadding="0" cellspacing="0" width="590" style="min-width: 590px; background-color: white; padding: 0px 8px 0px 8px; border-collapse:separate;"> + <tr><td style="padding-bottom: 24px;"><b>Halo Pak Akbar,</b></td></tr> + + <tr><td style="padding-bottom: 16px;">Kami sampaikan informasi bahwa saat ini terdapat pengajuan Pembayaran Tempo dari ${object.pengajuan_tempo_id.name_tempo.name} telah melalui tahap persetujuan awal dari Manager Sales & diverifikasi oleh ${object.write_uid.name} dari tim Finance.</td></tr> + + <tr><td style="padding-bottom: 16px;">Untuk proses persetujuan akhir, mohon Bapak dapat segera meninjau dan mengevaluasi atas pengajuan terhadap data yang telah diberikan oleh ${object.pengajuan_tempo_id.name_tempo.name}.</td></tr> + + <tr><td style="padding-bottom: 2px;"><b>Hormat kami,</b></td></tr> + <tr><td style="padding-bottom: 2px;">PT. INDOTEKNIK DOTCOM GEMILANG</td></tr> + <tr> + <td valign="middle" align="left"> + <img src="https://erp.indoteknik.com/api/image/ir.attachment/datas/2135765" alt="Indoteknik" style="max-width: 50%; height: auto;"></img> + </td> + </tr> + <tr> + <td style="text-align:center;"> + <hr width="100%" + style="background-color:rgb(204,204,204);border:medium none;clear:both;display:block;font-size:0px;min-height:1px;line-height:0; margin: 16px 0px 16px 0px;" /> + </td> + </tr> + </table> + </td> + </tr> + <!-- CONTENT --> + </tbody> + </table> + </td></tr> + </table> + </field> + </record> + <record id="mail_template_res_user_company_tempo_approved" model="mail.template"> + <field name="name">Users: Company Tempo Approved</field> + <field name="model_id" ref="indoteknik_custom.model_user_pengajuan_tempo_request"/> + <field name="subject">Pengajuan Tempo Anda di Indoteknik.com Telah Disetujui!</field> + <field name="email_from">"Indoteknik.com" <noreply@indoteknik.com></field> + <field name="reply_to">sales@indoteknik.com</field> + <field name="email_to">${object.user_id.email | safe}</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;"> + <tr><td align="center"> + <table border="0" cellpadding="0" cellspacing="0" width="590" style="font-size: 13px; padding: 16px; background-color: white; color: #454748; border-collapse:separate;"> + <!-- HEADER --> + <tbody> + <tr> + <td align="center" style="min-width: 590px;"> + <table border="0" cellpadding="0" cellspacing="0" width="590" style="min-width: 590px; background-color: white; padding: 0px 8px 0px 8px; border-collapse:separate;"> + <tr> + <td valign="middle"> + <span></span> + </td> + </tr> + + <tr> + <td colspan="2" style="text-align:center;"> + <hr width="100%" style="background-color:rgb(204,204,204);border:medium none;clear:both;display:block;font-size:0px;min-height:1px;line-height:0; margin: 16px 0px 16px 0px;" /> + </td> + </tr> + </table> + </td> + </tr> + <!-- CONTENT --> + <tr> + <td align="center" style="min-width: 590px;"> + <table border="0" cellpadding="0" cellspacing="0" width="590" style="min-width: 590px; background-color: white; padding: 0px 8px 0px 8px; border-collapse:separate;"> + <tr><td style="padding-bottom: 24px;"><b>Hai. ${object.pengajuan_tempo_id.name_tempo.name},</b></td></tr> + + <tr><td style="padding-bottom: 16px;">Kabar baik! Kami dengan senang hati menginformasikan bahwa pengajuan tempo pembayaran anda di Indoteknik.com telah disetujui dengan detail sebagai berikut.</td></tr> + <tr><td style="padding-bottom: 4px;"><b>Limit Pembayaran Tempo : Rp ${object.format_currency(object.user_id.tempo_limit)}</b></td></tr> + + <tr><td style="padding-bottom: 16px;"><b>Durasi Pembayaran Tempo : ${object.user_id.tempo_duration.name}</b></td></tr> + <tr> + <td style="padding-bottom: 16px; ">Anda dapat melakukan pembayaran sesuai dengan jangka waktu yang telah disepakati. Detail lengkap mengenai transaksi anda, termasuk tanggal jatuh tempo & Pengajuan Kenaikan Limit Tempo, dapat anda lihat di akun <a href="https://indoteknik.com/my/profile">Profile Indoteknik.com</a> .</td> + </tr> + + <tr><td style="padding-bottom: 16px;">Terima kasih atas kepercayaan anda kepada Indoteknik.com.</td></tr> + + <tr><td style="padding-bottom: 2px;"><b>Hormat kami,</b></td></tr> + <tr><td style="padding-bottom: 2px;">PT. INDOTEKNIK DOTCOM GEMILANG</td></tr> + <tr> + <td valign="middle" align="left"> + <img src="https://erp.indoteknik.com/api/image/ir.attachment/datas/2135765" alt="Indoteknik" style="max-width: 50%; height: auto;"></img> + </td> + </tr> + <tr> + <td style="text-align:center;"> + <hr width="100%" + style="background-color:rgb(204,204,204);border:medium none;clear:both;display:block;font-size:0px;min-height:1px;line-height:0; margin: 16px 0px 16px 0px;" /> + </td> + </tr> + </table> + </td> + </tr> + <!-- CONTENT --> + </tbody> + </table> + </td></tr> + </table> + </field> + </record> + <record id="mail_template_res_user_company_tempo_reject" model="mail.template"> + <field name="name">Users: Company Tempo Reject</field> + <field name="model_id" ref="indoteknik_custom.model_user_pengajuan_tempo_request"/> + <field name="subject">Mohon Maaf Pengajuan Tempo anda kami Tolak</field> + <field name="email_from">"Indoteknik.com" <noreply@indoteknik.com></field> + <field name="reply_to">sales@indoteknik.com</field> + <field name="email_to">${object.user_id.email | safe}</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;"> + <tr><td align="center"> + <table border="0" cellpadding="0" cellspacing="0" width="590" style="font-size: 13px; padding: 16px; background-color: white; color: #454748; border-collapse:separate;"> + <!-- HEADER --> + <tbody> + <tr> + <td align="center" style="min-width: 590px;"> + <table border="0" cellpadding="0" cellspacing="0" width="590" style="min-width: 590px; background-color: white; padding: 0px 8px 0px 8px; border-collapse:separate;"> + <tr> + <td valign="middle"> + <span></span> + </td> + </tr> + + <tr> + <td colspan="2" style="text-align:center;"> + <hr width="100%" style="background-color:rgb(204,204,204);border:medium none;clear:both;display:block;font-size:0px;min-height:1px;line-height:0; margin: 16px 0px 16px 0px;" /> + </td> + </tr> + </table> + </td> + </tr> + <!-- CONTENT --> + <tr> + <td align="center" style="min-width: 590px;"> + <table border="0" cellpadding="0" cellspacing="0" width="590" style="min-width: 590px; background-color: white; padding: 0px 8px 0px 8px; border-collapse:separate;"> + <tr><td style="padding-bottom: 24px;"><b>Hai. ${object.pengajuan_tempo_id.name_tempo.name},</b></td></tr> + + <tr><td style="padding-bottom: 16px;">Kami sampaikan dengan sangat menyesal bahwa pengajuan permohonan tempo pembayaran Anda yang diajukan pada tanggal ${format_date(object.pengajuan_tempo_id.create_date, 'dd MMMM yyyy')} tidak dapat kami setujui.</td></tr> + <tr><td style="padding-bottom: 16px;">Keputusan ini telah kami pertimbangkan secara matang berdasarkan beberapa faktor, diantaranya alasan tidak disetujuinya adalah ${object.reason_reject}</td></tr> + <tr> + <td style="padding-bottom: 16px; ">Kami memahami bahwa hal ini mungkin mengecewakan. Namun, kami berharap Anda dapat memahami kebijakan perusahaan kami.</td> + </tr><tr> + <td style="padding-bottom: 16px; ">Jangan khawatir anda dapat melakukan pembelian dengan metode pembayaran CBD (Cash Before Delivery) di website indoteknik.com.</td> + </tr> + + <tr><td style="padding-bottom: 16px;">Terima kasih atas Perhatian & Pengertiannya.</td></tr> + + <tr><td style="padding-bottom: 2px;"><b>Hormat kami,</b></td></tr> + <tr><td style="padding-bottom: 2px;">PT. INDOTEKNIK DOTCOM GEMILANG</td></tr> + <tr> + <td valign="middle" align="left"> + <img src="https://erp.indoteknik.com/api/image/ir.attachment/datas/2135765" alt="Indoteknik" style="max-width: 50%; height: auto;"></img> + </td> + </tr> + <tr> + <td style="text-align:center;"> + <hr width="100%" + style="background-color:rgb(204,204,204);border:medium none;clear:both;display:block;font-size:0px;min-height:1px;line-height:0; margin: 16px 0px 16px 0px;" /> + </td> + </tr> + </table> + </td> + </tr> + <!-- CONTENT --> + </tbody> + </table> + </td></tr> + </table> + </field> + </record> + + + <record id="action_user_pengajuan_tempo_request" model="ir.actions.act_window"> + <field name="name">User Pengajuan Tempo Request</field> + <field name="type">ir.actions.act_window</field> + <field name="res_model">user.pengajuan.tempo.request</field> + <field name="view_mode">tree,form</field> + </record> + + <menuitem + id="menu_user_pengajuan_tempo_request" + name="User Pengajuan Tempo Request" + parent="res_partner_menu_user" + sequence="3" + action="action_user_pengajuan_tempo_request" + /> +</odoo>
\ No newline at end of file |
