Membuat Custom Report di Odoo

Normalnya report di Odoo dibuat berdasarkan sebuah record di sebuah model seperti contoh disini. Akan tetapi adakalanya kita harus membuat report secara custom berdasarkan kebutuhan sistem yang sedang dibuat.

Kali ini saya akan membuat tutorial sebuah report yang menampilkan rekap presensi karyawan. Report yang dibuat ini menampilkan jumlah hari presensi dan jumlah hari absensi dalam rentang waktu periode tertentu.

Berikut ini adalah tampilan hasil akhir report yang akan dibuat:

Sebelum memulai, silakan membuat database baru dengan mencentang “Load demonstration data” agar ada data awal yang bisa kita gunakan untuk mengetes program. Lalu install modul hr_attendance. Modul tersebut adalah modul presensi bawaan dari Odoo. Dan jangan lupa memastikan bahwa wkhtmltopdf telah diinstall.

Berikut ini adalah tampilan awal setelah install hr_attendance:

Buat sebuah model untuk wizard di Odoo.

Buat sebuah model untuk wizard yang meng-inherit dari TransientModel.

from odoo import models, fields, api

class AttendanceReportWizard(models.TransientModel):
	_name = 'cj.attendance.report.wizard'

	date_start = fields.Date(string="Tanggal Awal", required=True, default=fields.Date.today)
	date_end = fields.Date(string="Tanggal Akhir", required=True, default=fields.Date.today)

	@api.multi
	def get_report(self):
		pass

Buat sebuah view untuk menampilkan wizard.

Buat sebuah view untuk menampilkan wizard berdasarkan model diatas.

<odoo>
	<data>
		<record model="ir.ui.view" id="view_attendance_report_wizard">
			<field name="name">attendance.report.wizard</field>
			<field name="model">cj.attendance.report.wizard</field>
			<field name="type">form</field>
			<field name="arch" type="xml">
				<form string="Laporan Rekap Presensi">
					<group>
						<group>
							<field name="date_start"/>
						</group>
						<group>
							<field name="date_end"/>
						</group>
					</group>
					<footer>
						<button name="get_report" string="Cetak Rekap PDF" type="object" class="btn-primary" attrs="{'invisible': ['|', ('date_start', '=', False), ('date_end', '=', False)]}"/>
						<button string="Batal" class="btn-default" special="cancel"/>
					</footer>
				</form>
			</field>
		</record>

		<act_window
			id="action_attendance_report_wizard"
			name="Laporan Rekap Presensi"
			res_model="cj.attendance.report.wizard"
			view_mode="form"
			target="new"/>

		<menuitem action="action_attendance_report_wizard" id="menu_attendance_report_wizard" parent="hr_attendance.menu_hr_attendance_report"/>
	</data>
</odoo>

Setelah membuat model dan view, maka seharusnya tampilan menu Attendance menjadi seperti ini:

Ubah class AttendanceReportWizard.

Setelah itu ubah class AttendanceReportWizard pada method get_report(), lalu buat model yang meng-inherit AbstractModel untuk membuat custom report. Hasil akhir file model yang dibuat adalah:

from datetime import datetime
from odoo import models, fields, api
from odoo.tools import DEFAULT_SERVER_DATE_FORMAT as DATE_FORMAT

class AttendanceReportWizard(models.TransientModel):
	_name = 'cj.attendance.report.wizard'

	date_start = fields.Date(string="Tanggal Awal", required=True, default=fields.Date.today)
	date_end = fields.Date(string="Tanggal Akhir", required=True, default=fields.Date.today)

	@api.multi
	def get_report(self):
		report_obj = self.env['report']
		template = 'cj_tutor_report.attendance_custom_report_view'
		report = report_obj._get_report_from_name(template)
		
		domain = {
			'date_start': self.date_start,
			'date_end': self.date_end,
		}
		
		vals = {
			'ids': self.ids,
			'model': report.model,
			'form': domain
		}

		"""get_action() otomatis akan memanggil render_html() di report"""
		return report_obj.get_action(self, template, data=vals)

class ReportAttendanceCustom(models.AbstractModel):
	"""
	# Report untuk menggenerate custom report
	# _name diisi dengan pola 'report.module_name.report_name'
	# _template diisi dengan pola 'module_name.report_name'
	"""

	_name = 'report.cj_tutor_report.attendance_custom_report_view'
	_template = 'cj_tutor_report.attendance_custom_report_view'

	@api.model
	def render_html(self, docids, data=None):
		if data is None:
			return

		date_start = data['form']['date_start']
		date_end = data['form']['date_end']

		report_obj = self.env['report']
		docs = self._get_rekap_data(date_start, date_end)

		LOCAL_FORMAT = '%d/%m/%Y'

		vals = {
			'docs': docs,
			'date_start': datetime.strptime(date_start, DATE_FORMAT).strftime(LOCAL_FORMAT),
			'date_end': datetime.strptime(date_end, DATE_FORMAT).strftime(LOCAL_FORMAT),
		}

		return report_obj.render(self._template, values=vals)

	def _get_rekap_data(self, date_start, date_end):
		"""
		return [
			{
				'employee': "employee 1 name",
				'presensi': count_of_presence,
				'absensi': count_of_absence,
			},
			{
				'employee': "employee 2 name",
				'presensi': count_of_presence,
				'absensi': count_of_absence,
			}
		]
		""" 

		date_start_obj = datetime.strptime(date_start, DATE_FORMAT).date()
		date_end_obj = datetime.strptime(date_end, DATE_FORMAT).date()
		date_count = (date_end_obj - date_start_obj).days + 1
		
		data = []

		# get all employee_data
		employees = self.env['hr.employee'].search([], order='name asc')
		for employee in employees:
			attendance_count = self.env['hr.attendance'].search_count([
				('employee_id', '=', employee.id),
				('check_in', '>=', date_start),
				('check_in', '<=', date_end)
			])

			selisih = date_count - attendance_count

			data.append({
				'employee': employee.name,
				'presensi': str(attendance_count) if attendance_count > 0 else '-',
				'absensi': str(selisih) if selisih > 0 else '-'
			})

		return data

Buat file view template report.

Setelah itu buat file view template report sesuai dengan report yang ingin ditampilkan.

<odoo>
	<data>
		<report id="cj_attendance_custom_report"
			model="cj.attendance.report.wizard"
			string="Laporan Rekap Presensi"
			report_type="qweb-pdf"
			name="cj_tutor_report.attendance_custom_report_view"
			file="cj_tutor_report.attendance_custom_report"
			menu="False"/>

		<record model="report.paperformat" id="paperformat_attendance_custom_report">
			<field name="name">paperformat.attendance.custom.report</field>
			<field name="default" eval="True" />
			<field name="format">A4</field>
			<field name="page_width">0</field>
			<field name="page_width">0</field>
			<field name="orientation">Portrait</field>
			<field name="margin_top">30</field>
			<field name="margin_right">5</field>
			<field name="margin_bottom">10</field>
			<field name="margin_left">5</field>
			<field name="header_line" eval="False"/>
			<field name="header_spacing">20</field>
			<field name="dpi">90</field> 
		</record>

		<!-- record id dibawah ini harus sama dengan report id -->
		<record id="cj_tutor_report.cj_attendance_custom_report" model="ir.actions.report.xml">
			<!-- field ref harus sama dengan id record paperformat -->
			<field name="paperformat_id" ref="cj_tutor_report.paperformat_attendance_custom_report"/>
		</record>

		<!-- template id dibawah ini harus sama dengan report name -->
		<template id="attendance_custom_report_view">
			<div class="header" style="border-bottom: 2px solid black">
				<h3 class="text-center">REKAPITULASI PRESENSI TEST CUSTOM REPORT</h3>
				<h4 class="text-center">
					Periode: <span t-esc="date_start"/> - <span t-esc="date_end"/>
				</h4>
			</div>

			<div class="page">
				<table class="table table-condensed table-bordered" style="width: 100%">
					<thead>
						<tr>
							<th class="text-center" style="width: 50%">Nama Karyawan</th>
							<th class="text-center" style="width: 25%">Jumlah Presensi</th>
							<th class="text-center" style="width: 25%">Jumlah Absensi</th>
						</tr>
					</thead>
					<tbody>
						<t t-foreach="docs" t-as="doc">
							<tr>
								<td><span t-esc="doc['employee']"/></td>
								<td class="text-center"><span t-esc="doc['presensi']"/></td>
								<td class="text-center"><span t-esc="doc['absensi']"/></td>
							</tr>
						</t>
					</tbody>
				</table>
			</div>

			<div class="footer">
				<div class="row text-center" style="border-top: 1px solid black;">
					<div class="col-xs-3 col-xs-offset-9 text-right">
						<ul class="list-inline" style="margin-top:10px;">
							<li>Hal:</li>
							<li><span class="page"/></li>
							<li>/</li>
							<li><span class="topage"/></li>
						</ul>
					</div>
				</div>
			</div>
		</template>
	</data>
</odoo>

Catatan: Saya menggunakan Odoo 10 dan wkhtmltopdf versi 0.12.0.

Untuk referensi report bisa dilihat dokumentasi Odoo. Dan kodingan diatas bisa dilihat repository github saya.

Terima kasih sudah membaca, semoga bermanfaat.

Comments

1 komentar untuk “Membuat Custom Report di Odoo”

  1. Ping-kembali: Membuat Custom Report di Odoo 11 - Cak Juice

Komentar ditutup.