diff --git a/gmn_freshservice/__manifest__.py b/gmn_freshservice/__manifest__.py
index ae40847..096f15a 100644
--- a/gmn_freshservice/__manifest__.py
+++ b/gmn_freshservice/__manifest__.py
@@ -20,6 +20,7 @@ Modul untuk melacak audit trail tiket dan memisahkan durasi penanganan:
'mail',
],
'data': [
+ 'security/gmn_freshservice_security_v01.xml',
'security/ir.model.access.csv',
'data/gmn_demo_data_v01.xml',
'views/gmn_res_config_settings_views_v01.xml',
diff --git a/gmn_freshservice/models/__pycache__/__init__.cpython-312.pyc b/gmn_freshservice/models/__pycache__/__init__.cpython-312.pyc
index 02ac545..209a667 100644
Binary files a/gmn_freshservice/models/__pycache__/__init__.cpython-312.pyc and b/gmn_freshservice/models/__pycache__/__init__.cpython-312.pyc differ
diff --git a/gmn_freshservice/models/__pycache__/gmn_freshservice_holiday_v01.cpython-312.pyc b/gmn_freshservice/models/__pycache__/gmn_freshservice_holiday_v01.cpython-312.pyc
index bb6d1c1..e1724d1 100644
Binary files a/gmn_freshservice/models/__pycache__/gmn_freshservice_holiday_v01.cpython-312.pyc and b/gmn_freshservice/models/__pycache__/gmn_freshservice_holiday_v01.cpython-312.pyc differ
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 120e87f..c98729a 100644
Binary files a/gmn_freshservice/models/__pycache__/gmn_freshservice_ticket_conversation_v01.cpython-312.pyc and b/gmn_freshservice/models/__pycache__/gmn_freshservice_ticket_conversation_v01.cpython-312.pyc differ
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 fd0a2f8..58424e6 100644
Binary files a/gmn_freshservice/models/__pycache__/gmn_freshservice_ticket_stage_log_v01.cpython-312.pyc and b/gmn_freshservice/models/__pycache__/gmn_freshservice_ticket_stage_log_v01.cpython-312.pyc differ
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 9967e7d..df6eaf0 100644
Binary files a/gmn_freshservice/models/__pycache__/gmn_freshservice_ticket_v01.cpython-312.pyc and b/gmn_freshservice/models/__pycache__/gmn_freshservice_ticket_v01.cpython-312.pyc differ
diff --git a/gmn_freshservice/models/gmn_freshservice_ticket_stage_log_v01.py b/gmn_freshservice/models/gmn_freshservice_ticket_stage_log_v01.py
index b5a4d52..31b44d9 100644
--- a/gmn_freshservice/models/gmn_freshservice_ticket_stage_log_v01.py
+++ b/gmn_freshservice/models/gmn_freshservice_ticket_stage_log_v01.py
@@ -314,7 +314,7 @@ class FreshserviceTicketStageLog(models.Model):
delay_cause = fields.Selection([
('it', 'Agent'), ('user', 'User'), ('none', 'None'),
], string='Delay Cause', default='none')
- automatic_responsibility = fields.Selection(related='responsibility', readonly=True)
+ automatic_responsibility = fields.Selection(related='responsibility', string='Tanggung Jawab Otomatis', readonly=True)
override_responsibility = fields.Selection([
('internal', 'Agent Active Work'), ('it_hold', 'Agent Hold & Discussion'), ('customer', 'Waiting on Requester'),
('user_after_auto_resolve', 'Waiting on User After Auto-Resolve'),
diff --git a/gmn_freshservice/security/gmn_freshservice_security_v01.xml b/gmn_freshservice/security/gmn_freshservice_security_v01.xml
new file mode 100644
index 0000000..d1fa9c4
--- /dev/null
+++ b/gmn_freshservice/security/gmn_freshservice_security_v01.xml
@@ -0,0 +1,55 @@
+
+
+
+
+ Freshservice
+ Modul Analisis Bottleneck & Audit Trail Tiket Freshservice
+ 25
+
+
+
+
+ Role
+ 10
+
+
+
+
+
+ Viewer / Agent IT
+ 10
+
+
+ Hak baca (Read) pada seluruh tiket, audit trail, percakapan, dan hari libur. Dapat mengakses wizard bottleneck report untuk generate laporan Excel.
+
+
+
+
+ Supervisor / IT Manager
+ 20
+
+
+
+ Hak penuh (CRUD) serta hak mengeksekusi sinkronisasi API, manual override, impor hari libur, dan ekspor laporan bottleneck.
+
+
diff --git a/gmn_freshservice/security/ir.model.access.csv b/gmn_freshservice/security/ir.model.access.csv
index 7dba08a..08e83a2 100644
--- a/gmn_freshservice/security/ir.model.access.csv
+++ b/gmn_freshservice/security/ir.model.access.csv
@@ -1,7 +1,12 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
-access_freshservice_ticket_user,freshservice.ticket.user,model_freshservice_ticket,base.group_user,1,1,1,1
-access_freshservice_ticket_stage_log_user,freshservice.ticket.stage.log.user,model_freshservice_ticket_stage_log,base.group_user,1,1,1,1
-access_freshservice_ticket_conversation_user,freshservice.ticket.conversation.user,model_freshservice_ticket_conversation,base.group_user,1,1,1,1
-access_freshservice_ticket_bottleneck_wizard_user,freshservice.ticket.bottleneck.wizard.user,model_freshservice_ticket_bottleneck_wizard,base.group_user,1,1,1,1
-access_freshservice_holiday_user,freshservice.holiday.user,model_freshservice_holiday,base.group_user,1,1,1,1
-access_freshservice_holiday_import_wizard_user,freshservice.holiday.import.wizard.user,model_freshservice_holiday_import_wizard,base.group_user,1,1,1,1
+access_freshservice_ticket_user,freshservice.ticket.user,model_freshservice_ticket,gmn_freshservice.group_freshservice_user,1,0,0,0
+access_freshservice_ticket_manager,freshservice.ticket.manager,model_freshservice_ticket,gmn_freshservice.group_freshservice_manager,1,1,1,1
+access_freshservice_ticket_stage_log_user,freshservice.ticket.stage.log.user,model_freshservice_ticket_stage_log,gmn_freshservice.group_freshservice_user,1,0,0,0
+access_freshservice_ticket_stage_log_manager,freshservice.ticket.stage.log.manager,model_freshservice_ticket_stage_log,gmn_freshservice.group_freshservice_manager,1,1,1,1
+access_freshservice_ticket_conversation_user,freshservice.ticket.conversation.user,model_freshservice_ticket_conversation,gmn_freshservice.group_freshservice_user,1,0,0,0
+access_freshservice_ticket_conversation_manager,freshservice.ticket.conversation.manager,model_freshservice_ticket_conversation,gmn_freshservice.group_freshservice_manager,1,0,0,0
+access_freshservice_holiday_user,freshservice.holiday.user,model_freshservice_holiday,gmn_freshservice.group_freshservice_user,1,0,0,0
+access_freshservice_holiday_manager,freshservice.holiday.manager,model_freshservice_holiday,gmn_freshservice.group_freshservice_manager,1,1,1,1
+access_freshservice_holiday_import_wizard_manager,freshservice.holiday.import.wizard.manager,model_freshservice_holiday_import_wizard,gmn_freshservice.group_freshservice_manager,1,1,1,1
+access_freshservice_ticket_bottleneck_wizard_user,freshservice.ticket.bottleneck.wizard.user,model_freshservice_ticket_bottleneck_wizard,gmn_freshservice.group_freshservice_user,1,1,1,1
+access_freshservice_ticket_bottleneck_wizard_manager,freshservice.ticket.bottleneck.wizard.manager,model_freshservice_ticket_bottleneck_wizard,gmn_freshservice.group_freshservice_manager,1,1,1,1
diff --git a/gmn_freshservice/services/__pycache__/__init__.cpython-312.pyc b/gmn_freshservice/services/__pycache__/__init__.cpython-312.pyc
index 5a35688..796d39f 100644
Binary files a/gmn_freshservice/services/__pycache__/__init__.cpython-312.pyc and b/gmn_freshservice/services/__pycache__/__init__.cpython-312.pyc differ
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 7788d48..1c0ea2e 100644
Binary files a/gmn_freshservice/services/__pycache__/gmn_freshservice_client_v01.cpython-312.pyc and b/gmn_freshservice/services/__pycache__/gmn_freshservice_client_v01.cpython-312.pyc differ
diff --git a/gmn_freshservice/views/gmn_freshservice_holiday_views_v01.xml b/gmn_freshservice/views/gmn_freshservice_holiday_views_v01.xml
index cd3968e..16f737c 100644
--- a/gmn_freshservice/views/gmn_freshservice_holiday_views_v01.xml
+++ b/gmn_freshservice/views/gmn_freshservice_holiday_views_v01.xml
@@ -12,19 +12,22 @@
type="object"
class="btn-primary"
icon="fa-upload"
- display="always"/>
+ display="always"
+ groups="gmn_freshservice.group_freshservice_manager"/>
+ display="always"
+ groups="gmn_freshservice.group_freshservice_manager"/>
+ display="always"
+ groups="gmn_freshservice.group_freshservice_manager"/>
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 60d71f7..69b42b0 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
@@ -61,7 +61,7 @@
-
+
diff --git a/gmn_freshservice/views/gmn_freshservice_ticket_views_v01.xml b/gmn_freshservice/views/gmn_freshservice_ticket_views_v01.xml
index b0a8f43..a4f5c8c 100644
--- a/gmn_freshservice/views/gmn_freshservice_ticket_views_v01.xml
+++ b/gmn_freshservice/views/gmn_freshservice_ticket_views_v01.xml
@@ -11,7 +11,8 @@
type="object"
string="Sync Freshservice Data"
class="btn-primary"
- icon="fa-refresh"/>
+ icon="fa-refresh"
+ groups="gmn_freshservice.group_freshservice_manager"/>
-
+
diff --git a/gmn_freshservice/wizard/__pycache__/__init__.cpython-312.pyc b/gmn_freshservice/wizard/__pycache__/__init__.cpython-312.pyc
index a66e8f3..8a9a794 100644
Binary files a/gmn_freshservice/wizard/__pycache__/__init__.cpython-312.pyc and b/gmn_freshservice/wizard/__pycache__/__init__.cpython-312.pyc differ
diff --git a/gmn_freshservice/wizard/__pycache__/gmn_freshservice_holiday_import_wizard_v01.cpython-312.pyc b/gmn_freshservice/wizard/__pycache__/gmn_freshservice_holiday_import_wizard_v01.cpython-312.pyc
index 2f05bb2..170fb4b 100644
Binary files a/gmn_freshservice/wizard/__pycache__/gmn_freshservice_holiday_import_wizard_v01.cpython-312.pyc and b/gmn_freshservice/wizard/__pycache__/gmn_freshservice_holiday_import_wizard_v01.cpython-312.pyc differ
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 d386250..05ed7bb 100644
Binary files a/gmn_freshservice/wizard/__pycache__/gmn_freshservice_ticket_bottleneck_wizard_v01.cpython-312.pyc and b/gmn_freshservice/wizard/__pycache__/gmn_freshservice_ticket_bottleneck_wizard_v01.cpython-312.pyc differ
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 299a12a..31680ef 100644
--- a/gmn_freshservice/wizard/gmn_freshservice_ticket_bottleneck_wizard_v01.py
+++ b/gmn_freshservice/wizard/gmn_freshservice_ticket_bottleneck_wizard_v01.py
@@ -54,9 +54,10 @@ class FreshserviceTicketBottleneckWizard(models.TransientModel):
date_from = fields.Date(string='Dari Tanggal Dibuat')
date_to = fields.Date(string='Sampai Tanggal Dibuat')
as_of = fields.Datetime(
- string='Cut-off As-Of (UTC)',
- help='Jika diisi, semua durasi stage log dipotong sampai timestamp ini. '
- 'Timestamp laporan ditampilkan dalam WIB (UTC+7).',
+ string='Batas Waktu Cut-Off (As-Of)',
+ help='Batas waktu simulasi retrospektif (opsional). '
+ 'Jika diisi, perhitungan durasi seluruh stage log dipotong sampai timestamp ini. '
+ 'Kosongkan untuk perhitungan real-time hingga saat ini.',
)
status_filter = fields.Selection([
@@ -82,6 +83,19 @@ class FreshserviceTicketBottleneckWizard(models.TransientModel):
file_name = fields.Char(string='Nama File', readonly=True)
bottleneck_summary_html = fields.Html(string='Ringkasan Analisis Bottleneck', readonly=True)
+ @api.model
+ def default_get(self, fields_list):
+ res = super().default_get(fields_list)
+ active_model = self.env.context.get('active_model')
+ active_id = self.env.context.get('active_id')
+ if active_model == 'freshservice.ticket' and active_id:
+ ticket = self.env['freshservice.ticket'].browse(active_id)
+ if ticket.exists():
+ res['ticket_id'] = ticket.id
+ if ticket.external_ticket_id:
+ res['external_ticket_id'] = ticket.external_ticket_id
+ return res
+
@api.onchange('ticket_id')
def _onchange_ticket_id(self):
"""Kalau user pilih tiket dari dropdown, otomatis isi nomor ID Freshservice-nya."""
@@ -376,9 +390,14 @@ class FreshserviceTicketBottleneckWizard(models.TransientModel):
# Header Title
ws1.merge_range('B2:H2', f'TICKET ANALYSIS REPORT #{t.external_ticket_id}', title_fmt)
+ cutoff_info = ""
+ if self.as_of:
+ from datetime import timedelta as _td
+ as_of_wib = (self.as_of + _td(hours=7)).strftime('%d-%m-%Y %H:%M')
+ cutoff_info = f" | Cut-off As-Of: {as_of_wib} WIB"
ws1.write(
'B3',
- f'Dicetak: {datetime.now().strftime("%d-%m-%Y %H:%M:%S")} | Dicetak oleh: {self.env.user.name}',
+ f'Dicetak: {datetime.now().strftime("%d-%m-%Y %H:%M:%S")} | Dicetak oleh: {self.env.user.name}{cutoff_info}',
subtitle_fmt
)
@@ -718,7 +737,12 @@ class FreshserviceTicketBottleneckWizard(models.TransientModel):
return str(dt)
row2 = 4
- for idx2, log in enumerate(t.stage_log_ids.sorted('start_date'), start=1):
+ current_idx2 = 0
+ for log in t.stage_log_ids.sorted('start_date'):
+ start, end = self._clipped_stage_interval(log, report_as_of)
+ if not start:
+ continue
+ current_idx2 += 1
resp = stage_resp_map.get(log.id, self._effective_responsibility(log))
if resp == 'internal':
resp_label = 'Agent Active Work'
@@ -758,9 +782,10 @@ class FreshserviceTicketBottleneckWizard(models.TransientModel):
cause_label = dict(log._fields['delay_cause'].selection).get(log.delay_cause, log.delay_cause or 'None')
verif_str = 'Yes' if (log.needs_verification or resp == 'needs_verification') else 'No'
- ws2.write(row2, 1, idx2, td_center_fmt)
- 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)
+ effective_end = end if (self.as_of and end) else log.end_date
+ ws2.write(row2, 1, current_idx2, td_center_fmt)
+ ws2.write(row2, 2, _to_wib_str(start), td_center_fmt)
+ ws2.write(row2, 3, _to_wib_str(effective_end), td_center_fmt)
ws2.write(row2, 4, log.stage_name or '-', td_fmt)
ws2.write(row2, 5, log.effective_status or log.stage_name or '-', td_fmt)
ws2.write(row2, 6, resp_label, resp_fmt)
@@ -796,10 +821,14 @@ class FreshserviceTicketBottleneckWizard(models.TransientModel):
ws3.write(3, col_idx, h, th_fmt)
row3 = 4
- for idx3, conv in enumerate(t.conversation_ids.sorted('created_at'), start=1):
+ current_idx3 = 0
+ for conv in t.conversation_ids.sorted('created_at'):
+ if report_as_of and conv.created_at and conv.created_at > report_as_of:
+ continue
+ current_idx3 += 1
sender_type_label = 'Requester (User)' if (conv.sender_type == 'customer' or conv.incoming) else 'Agent (IT)'
conv_wib_str = _to_wib_str(conv.created_at)
- ws3.write(row3, 1, idx3, td_center_fmt)
+ ws3.write(row3, 1, current_idx3, td_center_fmt)
ws3.write(row3, 2, conv_wib_str, td_center_fmt)
ws3.write(row3, 3, sender_type_label, normal_badge_fmt if conv.incoming else bn_badge_fmt)
ws3.write(row3, 4, conv.user_name or '-', td_fmt)
diff --git a/gmn_freshservice/wizard/gmn_freshservice_ticket_bottleneck_wizard_views_v01.xml b/gmn_freshservice/wizard/gmn_freshservice_ticket_bottleneck_wizard_views_v01.xml
index c1cbdb5..d32a3f0 100644
--- a/gmn_freshservice/wizard/gmn_freshservice_ticket_bottleneck_wizard_views_v01.xml
+++ b/gmn_freshservice/wizard/gmn_freshservice_ticket_bottleneck_wizard_views_v01.xml
@@ -25,14 +25,14 @@
-
-
+
-
-
+
+
+
@@ -44,6 +44,7 @@
+