From ef5ba7f159c2097aa403ba99b3de61132aca55f3 Mon Sep 17 00:00:00 2001 From: Madanil Date: Mon, 19 Oct 2026 10:15:38 +0700 Subject: [PATCH] [UPD] update colot template and logic UI --- ...ce_ticket_conversation_v01.cpython-312.pyc | Bin 1932 -> 1933 bytes ...rvice_ticket_stage_log_v01.cpython-312.pyc | Bin 20083 -> 20085 bytes ...mn_freshservice_ticket_v01.cpython-312.pyc | Bin 47201 -> 48309 bytes ...mn_res_config_settings_v01.cpython-312.pyc | Bin 3351 -> 3318 bytes ...mn_freshservice_ticket_conversation_v01.py | 2 +- .../gmn_freshservice_ticket_stage_log_v01.py | 2 +- .../models/gmn_freshservice_ticket_v01.py | 100 +++++++++------ .../models/gmn_res_config_settings_v01.py | 13 +- ...mn_freshservice_client_v01.cpython-312.pyc | Bin 18549 -> 18550 bytes .../services/gmn_freshservice_client_v01.py | 4 +- ...reshservice_ticket_stage_log_views_v01.xml | 9 +- .../gmn_freshservice_ticket_views_v01.xml | 66 +++++----- .../gmn_res_config_settings_views_v01.xml | 9 +- ...cket_bottleneck_wizard_v01.cpython-312.pyc | Bin 46582 -> 48086 bytes ...eshservice_ticket_bottleneck_wizard_v01.py | 114 +++++++++++++----- 15 files changed, 203 insertions(+), 116 deletions(-) diff --git a/gmn_freshservice/models/__pycache__/gmn_freshservice_ticket_conversation_v01.cpython-312.pyc b/gmn_freshservice/models/__pycache__/gmn_freshservice_ticket_conversation_v01.cpython-312.pyc index 975f7cc3f442252dd8a87f0f52c29c378ae530e5..120e87f189f3bbce781545e498e606e6cfa5ebc1 100644 GIT binary patch delta 48 zcmeC-@8#z`&CAQh00j5juV!uD$UB*tPaw27wMaoDD7COOwYX&ST4n=gMvck$*wz66 DXGssT delta 47 zcmeC>@8Rb?&CAQh00fyc&SY)c$UB*tmp`;PwMaq3xwN<>KX>ywW&>tM^~v|y)&T%V C>JHQZ diff --git a/gmn_freshservice/models/__pycache__/gmn_freshservice_ticket_stage_log_v01.cpython-312.pyc b/gmn_freshservice/models/__pycache__/gmn_freshservice_ticket_stage_log_v01.cpython-312.pyc index c9854861b54827eb80f3360c3d786e014841a1f7..090e26fbdbd0e58b0784174883611fd9d243bba9 100644 GIT binary patch delta 66 zcmex7hw7@!zsYS(!xrquI!O0n^DWy57 TDGI)+sU?|t>6@RJPZR?H;u{xd diff --git a/gmn_freshservice/models/__pycache__/gmn_freshservice_ticket_v01.cpython-312.pyc b/gmn_freshservice/models/__pycache__/gmn_freshservice_ticket_v01.cpython-312.pyc index 8eff2b67f134900a1ce0c7d77c3d33257d840b73..199746e635594a67b79103da737732564d3bcef7 100644 GIT binary patch delta 9202 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 delta 8664 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 diff --git a/gmn_freshservice/models/__pycache__/gmn_res_config_settings_v01.cpython-312.pyc b/gmn_freshservice/models/__pycache__/gmn_res_config_settings_v01.cpython-312.pyc index 02e777ac03d72f844b098e774aa2e068e7d1c089..2f5be3e12b5a920b8d9494cf065c1838cd7d7cd4 100644 GIT binary patch delta 545 zcmbO(^-YrZG%qg~0}!y(U(M>D$h(G%9mE5I&xa-+UMrO%m?E@Bcr`0TEQ&itq=g}h zr&3f?Y;qf;wV+~pZeDy^QEG8UacWUnW^(G}+l-BZsu-eWOg2Iq=%RX)*K>W-hR;Bfp-3M@aKH#QAfvbuNVG8A;8$tzcp$Dcp=^5f#OfRTiZ>)}CiC$~2RVFU zWtL&Pz#{R1gF#+*M%w(mnRz$(HE&2d-w+VK!CU@?lT{ulE&YLqK~{T)+kC&7eqd?G z8v>#?1VwM~Mt|XElLe}f{4Ais>cUuLHMx|>j8S#+8Xie0OOQ*fKm^EPw>WHa^HWN5 hQtgWDCg10gmvmxebYYyqc3ndEqJ-{O1~3<_901b8oe=;4 delta 544 zcmew+IbDkPG%qg~0}yPRcQ$M5MBX)AY#<&GeBL+l@LI7of~%P!{3z}ep%#WHo=Ra& zk;z?*)>2w&MXALZ#i>PQnaQc~C7H?DsU`7=r74*uldmy0O6lR2&S0{UGQ=&tm1(Dx zK5prHX0iIJ6tB$eM1>Tf&3Pq>dFeU|#hJw=sksWdsd?$?rFn_jiFrVw+|r!H;!K6K z{G!~%5(Tede?JAFn{zW2+>o5E05qT=QK2BUD5q4xF~C#7JGD|Fu{bAFPm{Tb6X^LO zPyiM20*PcsNLXyj_1|%yxnT_)Vqx|OcoJ$$m6hI=%ldHJ(Rh2+Y zeIT)t;WLnADAEHF954bD*u~Y8&v8qbx!w?P`NGa3!FGW~ 0: action['limit'] = sync_limit except Exception: diff --git a/gmn_freshservice/models/gmn_res_config_settings_v01.py b/gmn_freshservice/models/gmn_res_config_settings_v01.py index 3b36c9f..6bc148b 100644 --- a/gmn_freshservice/models/gmn_res_config_settings_v01.py +++ b/gmn_freshservice/models/gmn_res_config_settings_v01.py @@ -8,24 +8,25 @@ class ResConfigSettings(models.TransientModel): freshservice_url = fields.Char( string='Freshservice URL', - config_parameter='freshservice_ticket_audit.freshservice_url', + config_parameter='gmn_freshservice.freshservice_url', default='https://ptglobalmultimedianetwork.freshservice.com' ) freshservice_api_key = fields.Char( string='Freshservice API Key', - config_parameter='freshservice_ticket_audit.freshservice_api_key' + config_parameter='gmn_freshservice.freshservice_api_key' ) freshservice_sync_limit = fields.Integer( string='Limit Sinkronisasi Tiket', - config_parameter='freshservice_ticket_audit.freshservice_sync_limit', + config_parameter='gmn_freshservice.freshservice_sync_limit', default=200, help='Batas jumlah tiket terbaru yang ditarik dari Freshservice saat membuka halaman list tiket (default 200).' ) freshservice_use_mock = fields.Boolean( string='Gunakan Mock Data Engine', - config_parameter='freshservice_ticket_audit.freshservice_use_mock', - # default=True, - help='Jika dicentang, sistem menggunakan simulasi format JSON resmi Freshservice tanpa perlu API Key asli.' + config_parameter='gmn_freshservice.freshservice_use_mock', + default=False, + readonly=True, + help='Mode mock dinonaktifkan. Integrasi selalu menggunakan Live Freshservice API.' ) def action_test_freshservice_connection(self): diff --git a/gmn_freshservice/services/__pycache__/gmn_freshservice_client_v01.cpython-312.pyc b/gmn_freshservice/services/__pycache__/gmn_freshservice_client_v01.cpython-312.pyc index bcd200e40dcf77f9e07cc87c6313ad58e06bf13c..7788d48a96d79d4cb7ed09aec58aaac72d40e863 100644 GIT binary patch delta 73 zcmex5f$`e}M&8rByj%=Gz*2uTD`X?@Hzvsx<{E~0W{?;NR5EC?_}yZ-#i;K#S(^C^ YqwHn@mTD(Px5YhfjEr)Vd);3E0Mf@3!~g&Q delta 72 zcmex1f${4EM&8rByj%=GaIEJ-R@g?~Z%h(3%ry-0%pfrksASM&_PfP!i&1~F4D%O8 Xh0TI2)lQ5di+kM|85Jk@xxWAa^12jw diff --git a/gmn_freshservice/services/gmn_freshservice_client_v01.py b/gmn_freshservice/services/gmn_freshservice_client_v01.py index 01b6024..0448659 100644 --- a/gmn_freshservice/services/gmn_freshservice_client_v01.py +++ b/gmn_freshservice/services/gmn_freshservice_client_v01.py @@ -31,10 +31,10 @@ class FreshserviceClient: _agent_cache = {} _dept_cache = {} - def __init__(self, base_url="https://servicedesk.lyman.co.id", api_key="", use_mock=True): + def __init__(self, base_url="https://servicedesk.lyman.co.id", api_key="", use_mock=False): self.base_url = (base_url or "").rstrip("/") self.api_key = api_key or "" - self.use_mock = use_mock + self.use_mock = False def get_agent_name(self, agent_id): """Ambil nama agen IT Freshservice berdasarkan ID (dengan in-memory cache)""" diff --git a/gmn_freshservice/views/gmn_freshservice_ticket_stage_log_views_v01.xml b/gmn_freshservice/views/gmn_freshservice_ticket_stage_log_views_v01.xml index fec3f3b..55bd039 100644 --- a/gmn_freshservice/views/gmn_freshservice_ticket_stage_log_views_v01.xml +++ b/gmn_freshservice/views/gmn_freshservice_ticket_stage_log_views_v01.xml @@ -13,9 +13,10 @@ + decoration-info="responsibility == 'scheduled_meeting'" + decoration-muted="responsibility in ('third_party','external_activity','resolved_idle')"/> @@ -75,11 +76,11 @@ - + - + diff --git a/gmn_freshservice/views/gmn_freshservice_ticket_views_v01.xml b/gmn_freshservice/views/gmn_freshservice_ticket_views_v01.xml index 931c8d1..6b7a287 100644 --- a/gmn_freshservice/views/gmn_freshservice_ticket_views_v01.xml +++ b/gmn_freshservice/views/gmn_freshservice_ticket_views_v01.xml @@ -17,21 +17,10 @@ string="Laporan Bottleneck (Excel)" class="btn-outline-success" icon="fa-file-excel-o"/> - -
-
+
First Response -

- -

- - Oleh: - +

+ Oleh:
-
+
Agent -

- -

+

Waiting on Us
-
+
User -

- -

+

Waiting on Customer
-
+
+
+ Scheduled Meeting +

+ Waiting Together +
+
+
+
+ Third Party +

+ Waiting on Vendor +
+
+
Waktu Selesai -

- -

+

Total Resolution
@@ -115,9 +110,10 @@ decoration-muted="not is_active or responsibility in ('on_hold','third_party','internal_discussion','scheduled_meeting','external_activity','resolved_idle')"> + decoration-info="responsibility == 'scheduled_meeting'" + decoration-muted="responsibility in ('third_party','external_activity','resolved_idle')"/> @@ -159,7 +155,11 @@ + + + + @@ -204,6 +204,8 @@ decoration-success="current_responsibility == 'closed'"/> + + diff --git a/gmn_freshservice/views/gmn_res_config_settings_views_v01.xml b/gmn_freshservice/views/gmn_res_config_settings_views_v01.xml index d693eaa..c8d7604 100644 --- a/gmn_freshservice/views/gmn_res_config_settings_views_v01.xml +++ b/gmn_freshservice/views/gmn_res_config_settings_views_v01.xml @@ -7,7 +7,7 @@ - + @@ -21,12 +21,11 @@ - - +
@@ -42,6 +41,6 @@ res.config.settings form main - {'module': 'freshservice_ticket_audit'} + {'module': 'gmn_freshservice'} diff --git a/gmn_freshservice/wizard/__pycache__/gmn_freshservice_ticket_bottleneck_wizard_v01.cpython-312.pyc b/gmn_freshservice/wizard/__pycache__/gmn_freshservice_ticket_bottleneck_wizard_v01.cpython-312.pyc index 575a56305c1c5e132d7fda17ca3943242c5a6d22..560d3efe844fc4a6cd9bf9c4212bc64db8208517 100644 GIT binary patch delta 9003 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 N(^T?+qn2#>e*g`f@L&J{ diff --git a/gmn_freshservice/wizard/gmn_freshservice_ticket_bottleneck_wizard_v01.py b/gmn_freshservice/wizard/gmn_freshservice_ticket_bottleneck_wizard_v01.py index 5306235..6f36007 100644 --- a/gmn_freshservice/wizard/gmn_freshservice_ticket_bottleneck_wizard_v01.py +++ b/gmn_freshservice/wizard/gmn_freshservice_ticket_bottleneck_wizard_v01.py @@ -207,6 +207,11 @@ class FreshserviceTicketBottleneckWizard(models.TransientModel): 'bg_color': '#FCF3CF', 'font_color': '#7D6608', 'border': 1, 'border_color': '#F9E79F', 'align': 'center', 'valign': 'vcenter' }) + scheduled_meeting_fmt = workbook.add_format({ + 'bold': True, 'font_size': 9, 'font_name': 'Calibri', + 'bg_color': '#D6EAF8', 'font_color': '#21618C', 'border': 1, + 'border_color': '#85C1E9', 'align': 'center', 'valign': 'vcenter' + }) kpi_box_label = workbook.add_format({ 'font_size': 9, 'font_name': 'Calibri', 'bold': True, 'bg_color': '#EBF5FB', 'font_color': '#2874A6', 'border': 1, 'border_color': '#AED6F1' @@ -255,13 +260,15 @@ class FreshserviceTicketBottleneckWizard(models.TransientModel): summary_html = self._build_single_ticket_sheets( workbook, t, title_fmt, subtitle_fmt, section_fmt, th_fmt, td_fmt, td_wrap_fmt, td_center_fmt, td_num_fmt, td_dec_fmt, td_pct_fmt, td_date_fmt, - bn_badge_fmt, normal_badge_fmt, kpi_box_label, kpi_box_val, status_formats, sla_paused_fmt + bn_badge_fmt, normal_badge_fmt, kpi_box_label, kpi_box_val, status_formats, sla_paused_fmt, + scheduled_meeting_fmt ) else: summary_html = self._build_ranking_sheets( workbook, tickets, title_fmt, subtitle_fmt, section_fmt, th_fmt, td_fmt, td_wrap_fmt, td_center_fmt, td_num_fmt, td_dec_fmt, td_pct_fmt, td_date_fmt, - bn_badge_fmt, normal_badge_fmt, kpi_box_label, kpi_box_val, status_formats, sla_paused_fmt + bn_badge_fmt, normal_badge_fmt, kpi_box_label, kpi_box_val, status_formats, sla_paused_fmt, + scheduled_meeting_fmt ) workbook.close() @@ -309,7 +316,8 @@ class FreshserviceTicketBottleneckWizard(models.TransientModel): def _build_single_ticket_sheets( self, workbook, t, title_fmt, subtitle_fmt, section_fmt, th_fmt, td_fmt, td_wrap_fmt, td_center_fmt, td_num_fmt, td_dec_fmt, td_pct_fmt, td_date_fmt, - bn_badge_fmt, normal_badge_fmt, kpi_box_label, kpi_box_val, status_formats, sla_paused_fmt=None + bn_badge_fmt, normal_badge_fmt, kpi_box_label, kpi_box_val, status_formats, sla_paused_fmt, + scheduled_meeting_fmt ): """Membuat sheet untuk analisis mendalam bottleneck tiket tunggal.""" ws1 = workbook.add_worksheet('Ringkasan & Bottleneck KPI') @@ -404,12 +412,50 @@ class FreshserviceTicketBottleneckWizard(models.TransientModel): 'bg_color': '#FFFFFF', 'font_color': '#145A32', 'border': 1, 'border_color': '#A9DFBF', 'align': 'center', 'valign': 'vcenter' }) + # Warna KPI mengikuti responsibility: internal merah, customer orange, + # scheduled meeting biru, dan third party abu-abu. + kpi_internal_label = workbook.add_format({ + 'font_size': 9, 'font_name': 'Calibri', 'bold': True, + 'bg_color': '#FADBD8', 'font_color': '#922B21', 'border': 1, 'border_color': '#E6B0AA' + }) + kpi_customer_label = workbook.add_format({ + 'font_size': 9, 'font_name': 'Calibri', 'bold': True, + 'bg_color': '#FCF3CF', 'font_color': '#7D6608', 'border': 1, 'border_color': '#F9E79F' + }) + kpi_meeting_label = workbook.add_format({ + 'font_size': 9, 'font_name': 'Calibri', 'bold': True, + 'bg_color': '#D6EAF8', 'font_color': '#21618C', 'border': 1, 'border_color': '#85C1E9' + }) + kpi_third_party_label = workbook.add_format({ + 'font_size': 9, 'font_name': 'Calibri', 'bold': True, + 'bg_color': '#E5E7E9', 'font_color': '#566573', 'border': 1, 'border_color': '#BDC3C7' + }) + kpi_internal_val = workbook.add_format({ + 'font_size': 11, 'font_name': 'Calibri', 'bold': True, + 'bg_color': '#FDEDEC', 'font_color': '#922B21', 'border': 1, 'border_color': '#E6B0AA', + 'align': 'center', 'valign': 'vcenter' + }) + kpi_customer_val = workbook.add_format({ + 'font_size': 11, 'font_name': 'Calibri', 'bold': True, + 'bg_color': '#FEFDE8', 'font_color': '#7D6608', 'border': 1, 'border_color': '#F9E79F', + 'align': 'center', 'valign': 'vcenter' + }) + kpi_meeting_val = workbook.add_format({ + 'font_size': 11, 'font_name': 'Calibri', 'bold': True, + 'bg_color': '#EBF5FB', 'font_color': '#21618C', 'border': 1, 'border_color': '#85C1E9', + 'align': 'center', 'valign': 'vcenter' + }) + kpi_third_party_val = workbook.add_format({ + 'font_size': 11, 'font_name': 'Calibri', 'bold': True, + 'bg_color': '#F2F3F4', 'font_color': '#566573', 'border': 1, 'border_color': '#BDC3C7', + 'align': 'center', 'valign': 'vcenter' + }) ws1.write('B13', 'First Response', kpi_wh_label) ws1.write('C13', 'Total Waktu', kpi_wh_label) - ws1.write('D13', 'Waiting on Us (IT/Agent)', kpi_wh_label) - ws1.write('E13', 'Waiting on User (Pengguna)', kpi_wh_label) - ws1.write('F13', 'Total SLA Paused', kpi_wh_label) - ws1.write('G13', 'Resolved / Idle', kpi_wh_label) + ws1.write('D13', 'Waiting on Us (IT/Agent)', kpi_internal_label) + ws1.write('E13', 'Waiting on User (Requester)', kpi_customer_label) + ws1.write('F13', 'Scheduled Meeting', kpi_meeting_label) + ws1.write('G13', 'Third Party', kpi_third_party_label) ws1.write('H13', 'Catatan Rumus', kpi_wh_label) # Hitung jam kerja (UTC+7, 08:30-17:30, break 12:30-13:30, Senin-Jumat) @@ -450,10 +496,10 @@ class FreshserviceTicketBottleneckWizard(models.TransientModel): wh_total = sum(stage_wh_map.values()) ws1.write('B14', format_working_duration(wh_fr), kpi_box_val) ws1.write('C14', format_working_duration(wh_total), kpi_box_val) - ws1.write('D14', format_working_duration(wh_agent), kpi_box_val) - ws1.write('E14', format_working_duration(wh_cust), kpi_box_val) - ws1.write('F14', format_working_duration(wh_paused), kpi_box_val) - ws1.write('G14', format_working_duration(wh_resolved_idle), kpi_box_val) + ws1.write('D14', format_working_duration(wh_agent), kpi_internal_val) + ws1.write('E14', format_working_duration(wh_cust), kpi_customer_val) + ws1.write('F14', format_working_duration(wh_meeting), kpi_meeting_val) + ws1.write('G14', format_working_duration(wh_vendor), kpi_third_party_val) ws1.write('H14', 'Senin-Jumat, 08:30-17:30 WIB\nBreak 12:30-13:30 (8 Jam/Hari)\nDB UTC → +7 WIB', kpi_box_val) # REKAPITULASI BEBAN TANGGUNG JAWAB — harus identik dengan total Sheet 2. @@ -466,15 +512,17 @@ class FreshserviceTicketBottleneckWizard(models.TransientModel): recap_rows = [ ('Waiting on Us (IT - Pengerjaan Aktif)', 'Waktu penanganan langsung oleh Tim IT (Open / In Progress).', wh_it_direct), ('Waiting on Us (IT - Internal Hold & Discussion)', 'Tiket ditahan/dianalisa internal IT (Aturan 9: default Beban IT).', wh_internal_hold), - ('Waiting on User (Customer)', 'Menunggu balasan, konfirmasi, atau keputusan dari pemohon / user.', wh_cust), - ('Tunggu Bersama (Scheduled Meeting)', 'Masa tunggu bersama menjelang jadwal meeting / Zoom (SLA Paused).', wh_meeting), + ('Waiting on User (Requester)', 'Menunggu balasan, konfirmasi, atau keputusan dari pemohon / user.', wh_cust), + ('Scheduled Meeting (Waiting Together)', 'Masa tunggu bersama menjelang jadwal meeting / Zoom (SLA Paused).', wh_meeting), ('Waiting on Third Party (Vendor)', 'Eskalasi vendor eksternal atau pengerjaan pihak ketiga (SLA Paused).', wh_vendor), ('SLA Paused Lainnya (Admin / External)', 'Aktivitas jeda administratif sistemik lainnya.', wh_other_paused), ('Resolved / Idle Time (Sebelum Reopen)', 'Tiket telah di-resolve atau idle otomatis, tidak membebani pemohon.', wh_resolved_idle), ('Grand Total Umur Tiket', 'Jumlah seluruh tahapan; harus 100% sama dengan total Sheet 2.', wh_total), ] - for recap_row, (label, description, hours) in enumerate(recap_rows, start=18): - label_fmt = bn_badge_fmt if label.startswith('Waiting on Us') else (normal_badge_fmt if label.startswith('Waiting on User') else (section_fmt if label == 'Grand Total Umur Tiket' else (sla_paused_fmt or td_center_fmt))) + # xlsxwriter memakai indeks baris 0-based: start=17 berarti Excel row 18. + # Ini menghindari satu baris kosong sebelum rekap pertama. + for recap_row, (label, description, hours) in enumerate(recap_rows, start=17): + label_fmt = bn_badge_fmt if label.startswith('Waiting on Us') else (normal_badge_fmt if label.startswith('Waiting on User') else (scheduled_meeting_fmt if label.startswith('Scheduled Meeting') else (section_fmt if label == 'Grand Total Umur Tiket' else (sla_paused_fmt or td_center_fmt)))) ws1.write(recap_row, 1, label, label_fmt) ws1.merge_range(recap_row, 2, recap_row, 5, description, td_fmt) ws1.write(recap_row, 6, hours, td_dec_fmt) @@ -482,18 +530,19 @@ class FreshserviceTicketBottleneckWizard(models.TransientModel): ws1.write(recap_row, 8, (hours / wh_total) if wh_total else 0.0, td_pct_fmt) # TABEL RANKING BOTTLENECK PER STAGE - # Rekapitulasi berakhir di baris Excel 26 (grand total), sehingga - # ranking dimulai di baris 28 agar tidak overlap dengan merge C25:F25. - ws1.merge_range('B28:I28', 'RANKING BOTTLENECK PER STAGE (Diurutkan dari Tahapan Paling Lama)', section_fmt) + # Rekap berakhir di Excel row 25. Row 26 adalah pemisah. + # Title di Excel row 27 (index 26), header di Excel row 28 (index 27), + # dan data mulai di Excel row 29 (index 28) secara berurutan tanpa baris kosong. + ws1.merge_range('B27:I27', 'RANKING BOTTLENECK PER STAGE (Diurutkan dari Tahapan Paling Lama)', section_fmt) headers_bn = ['Rank', 'Tahapan / Status', 'Tanggung Jawab', 'Pengguna', 'Hari Kerja Efektif', 'Jam Kerja', '% Kontribusi', 'Status'] for col_idx, h in enumerate(headers_bn, start=1): - ws1.write(29, col_idx, h, th_fmt) + ws1.write(27, col_idx, h, th_fmt) sorted_stages = t.stage_log_ids.sorted(key=lambda s: stage_wh_map.get(s.id, 0.0), reverse=True) total_wh_ticket = max(0.01, sum(stage_wh_map.values()) or 0.01) - row = 30 + row = 28 primary_bn_text = "Tidak terdeteksi delay signifikan." primary_bn_actor = "-" primary_bn_stage = "-" @@ -508,6 +557,7 @@ class FreshserviceTicketBottleneckWizard(models.TransientModel): resp_fmt = bn_badge_fmt elif stage.responsibility == 'customer': resp_label = 'Waiting on User (Requester)' + # Customer selalu orange/kuning, bukan merah. resp_fmt = normal_badge_fmt elif stage.responsibility == 'on_hold': resp_label = 'On Hold (Internal Hold / Waiting on Us)' @@ -519,8 +569,8 @@ class FreshserviceTicketBottleneckWizard(models.TransientModel): resp_label = 'Waiting on Internal Discussion (Internal Hold / Waiting on Us)' resp_fmt = bn_badge_fmt elif stage.responsibility == 'scheduled_meeting': - resp_label = 'Tunggu Bersama (Scheduled Meeting - SLA is Paused)' - resp_fmt = sla_paused_fmt or td_center_fmt + resp_label = 'Scheduled Meeting (Waiting Together - SLA is Paused)' + resp_fmt = scheduled_meeting_fmt elif stage.responsibility == 'external_activity': resp_label = 'External Activity (SLA is Paused)' resp_fmt = sla_paused_fmt or td_center_fmt @@ -529,7 +579,8 @@ class FreshserviceTicketBottleneckWizard(models.TransientModel): resp_fmt = sla_paused_fmt or td_center_fmt is_primary = (rank_idx == 1 and stage_wh > 0.0) - ws1.write(row, 1, f"#{rank_idx}", bn_badge_fmt if is_primary else td_center_fmt) + # Nomor ranking utama mengikuti warna tanggung jawab bottleneck. + ws1.write(row, 1, f"#{rank_idx}", resp_fmt if is_primary else td_center_fmt) ws1.write(row, 2, stage.stage_name or '-', td_fmt) ws1.write(row, 3, resp_label, resp_fmt) ws1.write(row, 4, stage.actor_name or '-', td_fmt) @@ -579,7 +630,7 @@ class FreshserviceTicketBottleneckWizard(models.TransientModel): if log.responsibility == 'internal': resp_label = 'Waiting on Us (Internal)' elif log.responsibility == 'customer': - resp_label = 'Waiting on User (Customer)' + resp_label = 'Waiting on User (Requester)' elif log.responsibility == 'on_hold': resp_label = 'On Hold (Internal Hold / Waiting on Us)' elif log.responsibility == 'third_party': @@ -587,9 +638,9 @@ class FreshserviceTicketBottleneckWizard(models.TransientModel): elif log.responsibility == 'internal_discussion': resp_label = 'Waiting on Internal Discussion (Internal Hold / Waiting on Us)' elif log.responsibility == 'scheduled_meeting': - resp_label = 'Tunggu Bersama (Scheduled Meeting - SLA is Paused)' + resp_label = 'Scheduled Meeting (Waiting Together - SLA is Paused)' elif log.responsibility == 'external_activity': - resp_label = 'External Activity (SLA is Paused)' + resp_label = 'External Activity (SLA is Paused)' else: resp_label = 'Resolved (Ticket Closed/Idle)' msg_body = self._get_stage_conversation_body(log, t) @@ -615,7 +666,8 @@ class FreshserviceTicketBottleneckWizard(models.TransientModel): ws2.write(row2, 2, _to_wib_str(log.start_date), td_center_fmt) ws2.write(row2, 3, _to_wib_str(log.end_date), td_center_fmt) ws2.write(row2, 4, log.stage_name or '-', td_fmt) - ws2.write(row2, 5, resp_label, bn_badge_fmt if log.responsibility == 'internal' else (normal_badge_fmt if log.responsibility == 'customer' else (sla_paused_fmt or td_center_fmt))) + resp_fmt = bn_badge_fmt if log.responsibility in ('internal', 'on_hold', 'internal_discussion') else (normal_badge_fmt if log.responsibility == 'customer' else (scheduled_meeting_fmt if log.responsibility == 'scheduled_meeting' else (sla_paused_fmt or td_center_fmt))) + ws2.write(row2, 5, resp_label, resp_fmt) ws2.write(row2, 6, log.actor_type or '-', td_center_fmt) ws2.write(row2, 7, log.actor_name or '-', td_fmt) ws2.write(row2, 8, wd_eff, td_dec_fmt) @@ -832,8 +884,10 @@ class FreshserviceTicketBottleneckWizard(models.TransientModel): resp_label = 'On Hold (SLA is Paused)' elif log.responsibility == 'third_party': resp_label = 'Waiting on Third Party (SLA is Paused)' + elif log.responsibility == 'scheduled_meeting': + resp_label = 'Scheduled Meeting (Waiting Together - SLA is Paused)' else: - resp_label = 'Waiting on Internal Discussion (SLA is Paused)' + resp_label = 'Waiting on Internal Discussion (SLA is Paused)' msg_body = self._get_stage_conversation_body(log, t) raw_act_main = log.activity_content or '' if 'Isi Pesan:' in raw_act_main: @@ -856,7 +910,9 @@ class FreshserviceTicketBottleneckWizard(models.TransientModel): ws2.write(row2, 2, _wib(log.start_date), td_center_fmt) ws2.write(row2, 3, _wib(log.end_date), td_center_fmt) ws2.write(row2, 4, log.stage_name or '-', td_fmt) - ws2.write(row2, 5, resp_label, bn_badge_fmt if log.responsibility == 'internal' else (normal_badge_fmt if log.responsibility == 'customer' else (sla_paused_fmt or td_center_fmt))) + resp_fmt = bn_badge_fmt if log.responsibility in ('internal', 'on_hold', 'internal_discussion') else (normal_badge_fmt if log.responsibility == 'customer' else (scheduled_meeting_fmt if log.responsibility == 'scheduled_meeting' and scheduled_meeting_fmt else (sla_paused_fmt or td_center_fmt))) + # Waiting on User memakai normal_badge_fmt orange/kuning. + ws2.write(row2, 5, resp_label, resp_fmt) ws2.write(row2, 6, log.actor_name or '-', td_fmt) ws2.write(row2, 7, calc_log_days, td_num_fmt) ws2.write(row2, 8, log.duration_hours, td_dec_fmt)