Technical Documentation Aplikasi Jadwal Sholat Odoo 14 # Part 2
Bismillah,
Assalamu'alaikum Warohmatullah Wabarokatuh,

Pada kesempatan kali ini saya akan melanjutkan pembuatan aplikasi Jadwal Sholat Odoo 14.
Untuk yang belum mengikuti Technical Documentation Aplikasi Jadwal Sholat Odoo 14 # Part 1, silahkan dicoba terlebih dahulu.

Pada part 2 ini saya akan membahas konfigurasi dari aplikasi jadwal sholatnya yang akan kita tambahkan di tampilan backend.

1. Membuat object baru (res.city) untuk data Kota/Kabupaten

Tujuan membuat object baru untuk data Kota/Kabupaten karena default tidak ada object untuk menyimpan master data tersebut yang ada hanya Provinsi, sedangkan kita membutuhkan data ini untuk menyimpan konfigurasi jadwal sholat berdasarkan wilayah dari Kota/Kabupaten.

Data konfigurasi yang akan kita tambahkan diantaranya :

- Nama Kota/Kabupaten
- Provinsi (many2one ke object res.country.state)
- Longitude dan Latitude sebagai koordinat penentuan jadwal sholat
- Adjustment Menit Sholat 5 Waktu + waktu terbit dan waktu dhuha agar bisa disesuaikan jika ada perbedaan
- Penetapan waktu subuh, ashar dan isya

di dalam file models/models.py tambahkan code dibawah :

# -*- coding: utf-8 -*-

from odoo import models, fields, api

class ResCity(models.Model):
_name = 'res.city'

name = fields.Char('Kota/Kabupaten')
state_id = fields.Many2one('res.country.state', string='State (Provinsi)')
longitude = fields.Float('Longitude')
latitude = fields.Float('Latitude')
adj_fajr = fields.Float('Adjustment Subuh')
adj_sunrise = fields.Float('Adjustment Terbit')
adj_dzuhur = fields.Float('Adjustment Dzuhur')
adj_ashar = fields.Float('Adjustment Ashar')
adj_maghrib = fields.Float('Adjustment Maghrib')
adj_isya = fields.Float('Adjustment Isya')
angle_fajr = fields.Float('Penentapan Waktu Shubuh')
angle_isya = fields.Float('Penetapan Waktu Isya')
ashar_type = fields.Selection([("1","Panjang bayangan = tinggi benda (Syafi'i)"),("2","Panjang bayangan = 2x tinggi benda")], default="1", string="Penetapan Waktu Ashr")
dhuha_type = fields.Float('Waktu Dhuha')


Karena kita membuat object baru, jangan lupa tambahkan hak akses untuk object tersebut di security/ir.model.access.csv

id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_res_city,res_city,model_res_city,,1,1,1,1

Dan panggil filenya di __manifest__.py 



Kemudian kita buat tampilannya di xml 

<!-- KONFIGURASI KOTA/KABUPATEN -->

<record id="view_res_city_tree" model="ir.ui.view">
<field name="name">res.city.tree</field>
<field name="model">res.city</field>
<field name="arch" type="xml">
<tree>
<field name="name"/>
<field name="state_id"/>
</tree>
</field>
</record>

<record id="view_res_city_form" model="ir.ui.view">
<field name="name">res.city.form</field>
<field name="model">res.city</field>
<field name="arch" type="xml">
<form string="Kota/Kabupaten">
<sheet>
<group>
<group>
<field name="name" required="1"/>
<field name="state_id" required="1"/>
<label for="longitude"/>
<div class="o_row">
<field name="longitude"/>
<span>Derajat</span>
</div>
<label for="latitude"/>
<div class="o_row">
<field name="latitude"/>
<span>Derajat</span>
</div>
<label for="angle_fajr"/>
<div class="o_row">
<field name="angle_fajr"/>
<span>Derajat Kemiringan Matahari</span>
</div>
<field name="ashar_type"/>
<label for="angle_isya"/>
<div class="o_row">
<field name="angle_isya"/>
<span>Derajat Kemiringan Matahari</span>
</div>
</group>
<group>
<label for="adj_fajr"/>
<div class="o_row">
<field name="adj_fajr"/>
<span>Menit</span>
</div>
<label for="adj_sunrise"/>
<div class="o_row">
<field name="adj_sunrise"/>
<span>Menit</span>
</div>
<label for="dhuha_type"/>
<div class="o_row">
<field name="dhuha_type"/>
<span>Menit setelah Terbit</span>
</div>
<label for="adj_dzuhur"/>
<div class="o_row">
<field name="adj_dzuhur"/>
<span>Menit</span>
</div>
<label for="adj_ashar"/>
<div class="o_row">
<field name="adj_ashar"/>
<span>Menit</span>
</div>
<label for="adj_maghrib"/>
<div class="o_row">
<field name="adj_maghrib"/>
<span>Menit</span>
</div>
<label for="adj_isya"/>
<div class="o_row">
<field name="adj_isya"/>
<span>Menit</span>
</div>
</group>
</group>
</sheet>
</form>
</field>
</record>

<record model="ir.actions.act_window" id="res_city_action">
<field name="name">Kota/Kabupaten</field>
<field name="res_model">res.city</field>
<field name="view_mode">tree,form</field>
</record>

<!-- ========================== -->

    <menuitem id="menu_base_config" name="Pengaturan" parent="main_menu_jadwal_sholat" sequence="1"/>
<menuitem id="menu_city" name="Wilayah" action="res_city_action" parent="menu_base_config" sequence="2"/>


Berikut hasil tampilannya 



2. Inherit object res.partner untuk menambahkan many2one ke object Kota/Kabupaten (res.city)

Sebenarnya di res.partner sudah ada field city yang fungsinya untuk menyimpan nama kota tapi field tersebut berbentuk char, sedangkan kita membutuhkan field many2one untuk menyimpan konfigurasi dari waktu sholatnya per wilayah, jadi kita akan gantikan field city yang char dengan field city_id yang many2one. 

Selain kita gantikan field city dengan city_id, kita juga tambahkan onchange pada field city_id yang berfungsi untuk mengisikan field city, karena field ini nnti yang akan muncul di tampilan form company

di dalam file models/models.py tambahkan code di bawah :

class ResPartner(models.Model):
_inherit = 'res.partner'

city_id = fields.Many2one('res.city', string="Kota/Kabupaten")

@api.onchange('city_id')
def change_city(self):
self.city = self.city_id.name

Kemudian kita inherit form res.partner di xml 

<!-- INHERIT FORM PARTNER -->

<record id="view_partner_form_jaska_inherit" model="ir.ui.view">
<field name="name">res.prtner.jaska.inherit</field>
<field name="model">res.partner</field>
<field name="inherit_id" ref="base.view_partner_form"/>
<field name="arch" type="xml">
<field name="city" position="attributes">
<attribute name="invisible">1</attribute>
</field>
<field name="state_id" position="after">
<field name="city_id" domain="[('state_id','=',state_id)]"/>
</field>
</field>
</record>

<!-- ========================== -->

Berikut hasil tampilannya 



3. Inherit object res.company untuk konfigurasi tampilan display

kita akan menggunakan object res.company sebagai tempat untuk konfigurasi tampilan display secara umum, seperti :

- Waktu iqomah
- Timer Menjelang Adzan
- Adjustment Tanggal Hijriyah
- Waktu Transisi Background
- Auto Sync Color dengan warna dominasi gambar background
- Warna Dasar
- List Gambar Background
- Informasi Running Text
- Warna Text Header
- Munculkan Alamat
- Full Background Screen
- Kota/Kabupaten

Untuk saat ini, konfigurasinya akan kita tambahkan terlebih dahulu field - fieldnya, dan insyaAllah pada kesempatan yang akan datang akan kita terapkan di tampilan display-nya. 
Disini kita juga membuat 2 object baru yaitu information.line untuk menyimpan informasi running text yang berisi ayat Al-Qur'an, Hadits atau Maklumat/Informasi. Object yang kedua adalah background.list untuk menyimpan gambar background yang bisa kita set gambar tersebut menjadi background dasar, menjadi background saat timer menjelang adzan atau menjadi background saat timer menjelang iqomah.

di dalam object res.company kita tambahkan onchange dari field city_id yang fungsinya sama seperti yang ada di res.partner, serta kita tambahkan method get_settings sebagai 'Penjembatan' antara data konfigurasi yang ada di tampilan backend ke tampilan frontend yang akan kita buat.

di dalam file models/models.py tambahkan code di bawah:

class ResCompany(models.Model):
_inherit = 'res.company'

iqomah_timer = fields.Float(string="Waktu Iqomah")
next_adzan_timer = fields.Float(string="Timer Menjelang Adzan")
adj_hijriyah = fields.Integer(string="Adjustment Hijriyah")
background_timer = fields.Float(string="Waktu Background", default=0.25)
timer_sound = fields.Binary('Timer Sound')
auto_sync_color = fields.Boolean('Auto Sync Color Background', default=True)
base_color = fields.Char('Base Color', default="#867584")
background_line = fields.One2many('background.list', 'company_id', string="Background")
information_line = fields.One2many('information.line', 'company_id', string="Running Text")
adj_display_date = fields.Datetime('Adjust Display Time')
header_text_color = fields.Char('Time Text Color', default="#FFFFFF")
show_address = fields.Boolean('Show Address', default=True)
full_bg_image = fields.Boolean('Full Background Screen', default=True)
city_id = fields.Many2one(string='Kota', related="partner_id.city_id", store=True, readonly=False)

@api.onchange('city_id')
def change_city(self):
self.city = self.city_id.name

def get_settings(self, company_id):
result = {}
if company_id:
company_id = int(company_id)
company = self.browse(company_id)
result = {
'company': company.read()[0],
'adjustment': {} if not company.partner_id.city_id else company.partner_id.city_id.read()[0],
}
return result

jangan lupa tambahkan hak akses untuk 2 object baru yang kita buat di security/ir.model.access.csv

id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_res_city,res_city,model_res_city,,1,1,1,1
access_information_line,information_line,model_information_line,,1,1,1,1
access_background_list,background_list,model_background_list,,1,1,1,1


Kemudian kita inherit tampilannya di xml 

    <!-- INHERIT FORM COMPANY -->

<record id="view_company_jaska_inherit" model="ir.ui.view">
<field name="name">res.company.jaska.inherit</field>
<field name="model">res.company</field>
<field name="inherit_id" ref="base.view_company_form"/>
<field name="arch" type="xml">
<field name="city" position="attributes">
<attribute name="invisible">1</attribute>
</field>
<field name="state_id" position="after">
<field name="city_id" domain="[('state_id','=',state_id)]" required="1"/>
</field>
<field name="partner_id" position="after">
<field name="show_address"/>
</field>
<field name="favicon" position="after">
<field name="auto_sync_color"/>
<field name="base_color" widget="color" attrs="{'invisible':[('auto_sync_color','=',True)]}"/>
<field name="header_text_color" widget="color"/>
<label for="adj_hijriyah"/>
<div class="o_row">
<field name="adj_hijriyah"/>
<span>Hari</span>
</div>
<field name="next_adzan_timer" widget="float_time"/>
<field name="iqomah_timer" widget="float_time"/>
<field name="background_timer" widget="float_time"/>
<field name="full_bg_image"/>
<field name="background_line">
<tree editable="bottom">
<field name="background" widget="image" class="oe_avatar" style="float:left"/>
<field name="bg_iqomah"/>
<field name="bg_before_adzan"/>
</tree>
</field>
</field>
<field name="partner_id" position="attributes">
<attribute name="groups"></attribute>
</field>
<page name="general_info" position="after">
<page name="jaska_information" string="Al Qur'an / Hadits / Maklumat">
<field name="information_line">
<tree editable="bottom">
<field name="type"/>
<field name="name"/>
</tree>
</field>
</page>
</page>
</field>
</record>

<!-- ========================== -->

    <menuitem id="menu_company_config" name="Masjid" action="base.action_res_company_form" parent="menu_base_config" sequence="1"/>


Berikut hasil tampilannya



4. Menampilkan waktu sholat sesuai konfigurasi di display

Jika 3 langkah diatas sudah dilakukan, sekarang kita akan tampilkan waktu sholatnya di display berdasarkan konfigurasi yang sudah kita buat.

buat file js jadwal_sholat.js dan tempatkan file nya di static/src/ kemudian tambahkan code ini di dalamnya :

odoo.define('ab_jadwal_sholat.jadwal_sholat', function (require) {
"use strict";
var rpc = require('web.rpc');
var adhan = require('ab_jadwal_sholat.adzan');
var settings = {}
var d = new Date(),
hour = d.getHours(),
minute = d.getMinutes(),
second = d.getSeconds(),
day = d.getDay(),
date = d.getDate(),
month = d.getMonth(),
year = d.getFullYear(),
hari = new Array("Ahad", "Senin", "Selasa", "Rabu", "Kamis", "Jum'at", "Sabtu"),
bulan = new Array("Januari", "Februari", "Maret", "April", "Mei", "Juni", "Juli", "Agustus",
"September", "Oktober", "November", "Desember");
$().ready(function () {
        var company = $('#company').text();
var longitude = 0,
latitude = 0,
fajrAngle = 0,
ishaAngle = 0,
adj_fajr = 0,
adj_sunrise = 0,
adj_dhuha = 0,
adj_dzuhur = 0,
adj_ashar = 0,
adj_maghrib = 0,
adj_isya = 0,
ashar_type = 1;

        rpc.query({
model: "res.company",
method: "get_settings",
args: [false, company],
}).then(function (data) {
settings = data;

            var jadwal_sholat = SetPrayerTimes(settings);

});
function SetPrayerTimes(settings){
if (Object.keys(settings).length > 1){
latitude = settings['adjustment']['latitude'];
longitude = settings['adjustment']['longitude'];
ashar_type = settings['adjustment']['ashar_type'];
fajrAngle = settings['adjustment']['angle_fajr'];
ishaAngle = settings['adjustment']['angle_isya'];
adj_fajr = settings['adjustment']['adj_fajr'];
adj_sunrise = settings['adjustment']['adj_sunrise'];
adj_dhuha = settings['adjustment']['dhuha_type'];
adj_dzuhur = settings['adjustment']['adj_dzuhur'];
adj_ashar = settings['adjustment']['adj_ashar'];
adj_maghrib = settings['adjustment']['adj_maghrib'];
adj_isya = settings['adjustment']['adj_isya'];
}

let coordinates = new adhan.Coordinates(longitude, latitude);
var params = adhan.CalculationMethod.Other();
params.madhab = parseInt(ashar_type);
params.fajrAngle = fajrAngle;
params.ishaAngle = ishaAngle;
params.adjustments.fajr = adj_fajr;
params.adjustments.sunrise = adj_sunrise;
params.adjustments.dhuha = adj_dhuha;
params.adjustments.dhuhr = adj_dzuhur;
params.adjustments.asr = adj_ashar;
params.adjustments.maghrib = adj_maghrib;
params.adjustments.isha = adj_isya;
Date.prototype.addDays = function(days) {
this.setDate(this.getDate() + parseInt(days));
return this;
};
var prayerTimes = new adhan.PrayerTimes(coordinates, d, params);
var formattedTime = adhan.Date.formattedTime;
function addDhuha(sunriseFormattedTime, interval) {
function D(J){ return (J<10? '0':'') + J;};
var piece = sunriseFormattedTime.split(':');
var mins = piece[0]*60 + +piece[1] + +interval;
return D(mins%(24*60)/60 | 0) + ':' + D(mins%60);
};
// common adzan time
var _subuh = formattedTime(prayerTimes.fajr, +7, '24h');
var _sunrise = formattedTime(prayerTimes.sunrise, +7, '24h');
var _dhuha = addDhuha(_sunrise, params.adjustments.dhuha);
var _duhur = formattedTime(prayerTimes.dhuhr, +7, '24h');
var _ashar = formattedTime(prayerTimes.asr, +7, '24h');
var _maghrib = formattedTime(prayerTimes.maghrib, +7, '24h');
var _isya = formattedTime(prayerTimes.isha, +7, '24h');
var dzuhur_jumat = hari[day] === "Jum'at" ? "Jum'at" : "Dzuhur";
$('.subuh-text').html(`${_subuh}`);
$('.sunrise-text').html(`${_sunrise}`);
$('.dhuha-text').html(`${_dhuha}`);
$('.dzuhur-jumat').html(`${dzuhur_jumat}`);
$('.duhur-text').html(`${_duhur}`);
$('.ashar-text').html(`${_ashar}`);
$('.maghrib-text').html(`${_maghrib}`);
$('.isya-text').html(`${_isya}`);
        }
$('.day').html(`${hari[day]}`);
$('.date').html(`${date} ${bulan[month]} ${year}`);
setInterval(() => {
var datenow = `${date} ${bulan[month]} ${year}`;
var jDate = $('.date').html();
var $date = $('.date');
$('.day').html(`${hari[day]}`);
$('.date').html(datenow);

}, 5000);
setInterval(() => {
second++;
if (second === 60) { second = 0; minute++; }
if (minute === 60) { minute = 0; hour++; }
if (hour === 24) {
hour = 0; minute = 0; second = 0; setTimeout(() => {
location.reload();
}, 500);
};
var hour_padded = hour.toString().padStart(2,'0');
var minute_padded = minute.toString().padStart(2,'0');
var second_padded = second.toString().padStart(2,'0');
var time = hour_padded + ':' + minute_padded;
$('.hour').html(hour_padded);
$('.minute').html(minute_padded);
$('.second').html(second_padded);
}, 1000);
});
});

Jangan lupa panggil file js-nya di views/templates.xml

<template id="assets_common" name="Jadwal Sholat assets" inherit_id="web.assets_common">
<xpath expr="//script[last()]" position="after">
<script type="text/javascript" src="/ab_jadwal_sholat/static/src/js/adzan.js"></script>
<script type="text/javascript" src="/ab_jadwal_sholat/static/src/js/jadwal_sholat.js"></script>
</xpath>
</template>

Kemudian kita tambahkan di xmlnya untuk tampilan display di static/src/xml/jadwal_sholat_views.xml

<?xml version="1.0" encoding="UTF-8"?>
<odoo>
<template id="jadwal_sholat_view" name="Jadwal Sholat view">
<head>
<t t-call-assets="web.assets_common" t-js="false"/>
<t t-call-assets="web.assets_common" t-css="false"/>
</head>
<body>
<h1 style="font-size:45px">
<div><span class="day"></span></div>
<div><span class="date"></span></div>
<div class="time">
<span class="hour">00</span>:<span class="minute">00</span>:<span class="second">00</span>
</div>
</h1>
<table style="border: 1px solid;font-size:30px;">
<tr>
<th>Subuh</th>
<th>Terbit</th>
<th>Dhuha</th>
<th class="dzuhur-jumat"/>
<th>Ashar</th>
<th>Maghrib</th>
<th>Isya</th>
</tr>
<tr>
<td class="subuh-text"/>
<td class="sunrise-text"/>
<td class="dhuha-text"/>
<td class="duhur-text"/>
<td class="ashar-text"/>
<td class="maghrib-text"/>
<td class="isya-text"/>
</tr>
</table>
<span id="company" t-esc="company.id" style="display: none;"/>
</body>
</template>
</odoo>



Berikut ini hasil dari tampilan display-nya 



Terima kasih, semoga bermanfaat.
Kahfi
Wassalamu'alaikum Warohmatullah Wabarokatuh,
Cara Menghilangkan Button Default Create dan Edit berdasarkan kondisi state
ODOO 14