Commit c896cc17 by aa.gusti

idg_letter

1 parent a9e117e3
Showing 193 changed files with 2627 additions and 8372 deletions
Code,Account Name,Type,Allow Reconciliation,
11110001,Cash,Bank and Cash,FALSE,
11110002,Outstanding Receipts,Current Assets,TRUE,
11110003,Outstanding Payments,Current Assets,TRUE,
11110010,Petty Cash,Bank and Cash,TRUE,
11110020,Cash in Hand,Bank and Cash,TRUE,
11120001,Bank Suspense Account,Current Liabilities,FALSE,
11120002,Bank,Bank and Cash,FALSE,
11120003,Outstanding Receipts,Current Assets,TRUE,
11120004,Outstanding Payments,Current Assets,TRUE,
11120010,Personal Mandiri,Bank and Cash,TRUE,
11120020,Business Mandiri,Bank and Cash,TRUE,
11120030,Muamalat,Bank and Cash,TRUE,
11120040,BNI,Bank and Cash,TRUE,
11120050,BCA,Bank and Cash,TRUE,
11120060,BNI Giro,Bank and Cash,TRUE,
11120070,Mandiri Giro,Bank and Cash,TRUE,
11210010,Account Receivable,Receivable,TRUE,
11210011,Account Receivable (PoS),Receivable,TRUE,
11210020,Employee Liabilities,Current Assets,TRUE,
11300010,Meat Inventory,Current Assets,FALSE,
11300020,Fish Inventory,Current Assets,FALSE,
11300030,Vegetables Inventory,Current Assets,FALSE,
11300040,Dried Goods Inventory,Current Assets,FALSE,
11300050,Fruit Inventory,Current Assets,FALSE,
11300060,Fresh Drink Inventory,Current Assets,FALSE,
11300070,Cigarette Inventory,Current Assets,FALSE,
11300080,Food Inventory,Current Assets,FALSE,
11300090,Drink Inventory,Current Assets,FALSE,
11300100,Processed Food Inventory,Current Assets,FALSE,
11300110,Toiletries Inventory,Current Assets,FALSE,
11300120,"Book, Office Stationery, Accessories Inventory",Current Assets,FALSE,
11300130,Fashion & Textile Inventory,Current Assets,FALSE,
11300140,Cleaning Supplies Inventory,Current Assets,FALSE,
11300150,House Supplies Inventory,Current Assets,FALSE,
11300160,Electronic Inventory,Current Assets,FALSE,
11300170,Toys Inventory,Current Assets,FALSE,
11300180,Other Inventory,Current Assets,FALSE,
11410010,Building Rent,Prepayments,FALSE,
11410020,Prepaid Insurance,Prepayments,FALSE,
11410030,Prepaid Advertisement-Free,Prepayments,FALSE,
11510010,Prepaid Tax Pph 22,Prepayments,FALSE,
11510020,Prepaid Tax Pph 23,Prepayments,FALSE,
11510030,Prepaid Tax Pph 25,Prepayments,FALSE,
11800000,Down Payment,Prepayments,FALSE,
12110030,Owner Receivable,Current Assets,TRUE,
12110040,Other Receivable,Current Assets,TRUE,
12210010,Land,Prepayments,FALSE,
12210020,Office Building,Prepayments,FALSE,
12210030,Vehicle,Prepayments,FALSE,
12210040,Office Supplies,Prepayments,FALSE,
12210050,Software,Prepayments,FALSE,
12210060,Office Furniture,Prepayments,FALSE,
12281010,Accumulation Building Depreciation,Prepayments,FALSE,
12281020,Accumulation Vehicle Depreciation,Prepayments,FALSE,
12281030,Accumulation Office Supplies Depreciation,Prepayments,FALSE,
12281040,Accumulation Software Depreciation,Prepayments,FALSE,
12281050,Accumulation Office Furniture Depreciation,Prepayments,FALSE,
19999991,Liquidity Transfer,Current Assets,TRUE,
21100010,Trade Receivable,Payable,TRUE,
21100020,Shareholder Deposit,Current Liabilities,FALSE,
21100030,Third-Party Deposit,Current Liabilities,FALSE,
21100040,Salary Deposit,Current Liabilities,FALSE,
21210010,Tax Payable Pph 21,Current Liabilities,FALSE,
21210020,Tax Payable Pph 23,Current Liabilities,FALSE,
21210030,Tax Payable Pph 25,Current Liabilities,FALSE,
21210040,Tax Payable 4 (2),Current Liabilities,FALSE,
21210050,Tax Payable Pph 29,Current Liabilities,FALSE,
21221010,VAT Purchase,Current Liabilities,FALSE,
21221020,VAT Sales,Current Liabilities,FALSE,
22110010,Bank Loan,Current Liabilities,FALSE,
22110020,Leasing Deposit,Current Liabilities,FALSE,
25110010,Accrued Payable Electricity,Current Liabilities,FALSE,
25110020,Accrued Payable Jamsostek,Current Liabilities,FALSE,
25110030,Accrued Payable Water,Current Liabilities,FALSE,
25110040,Accrued Payable Telp & Internet,Current Liabilities,FALSE,
25110050,Accrued Payable Security Management,Current Liabilities,FALSE,
25110060,Accrued Payable Bank,Current Liabilities,FALSE,
25110070,Accrued Payable PBB,Current Liabilities,FALSE,
25110080,Accrued Payable Business License,Current Liabilities,FALSE,
25110090,Accrued Payable Insurance,Current Liabilities,FALSE,
25110100,Accrued Payable Education,Current Liabilities,FALSE,
25110110,Accrued Payable Health Insurance/BPJS,Current Liabilities,FALSE,
28110010,Advance Sales,Current Liabilities,FALSE,
28110020,Customer Deposit,Current Liabilities,FALSE,
28110030,Bonus Point,Current Liabilities,FALSE,
29000000,Interim Stock,Current Liabilities,FALSE,
31100010,Authorized Capital,Equity,FALSE,
31100020,Paid Capital,Equity,FALSE,
31100030,Unpaid Capital,Equity,FALSE,
31100040,Prive (Personal Retrieval),Equity,FALSE,
31210010,Capital Reserves,Equity,FALSE,
31510010,Past Profit & Loss,Equity,FALSE,
31510020,Ongoing Profit & Loss,Equity,FALSE,
39000000,Historical Balance,Equity,TRUE,
41000010,Sales,Income,FALSE,
41000020,Pajak Hotel Melati 1,Income,FALSE,
42000060,Sales Refund,Income,FALSE,
42000070,Sales Discount,Income,FALSE,
51000010,Cost of Goods Sold,Cost of Revenue,FALSE,
61100010,Employee Salary,Expenses,FALSE,
61100020,Employee Bonus / Benefits,Expenses,FALSE,
61100030,Employee Health Benefits,Expenses,FALSE,
61100040,Employee Meal (Catering),Expenses,FALSE,
61100050,Employee Overtime Pay,Expenses,FALSE,
61100060,Security Service Fee,Expenses,FALSE,
61100070,Work Uniform,Expenses,FALSE,
61100080,Employee Birthday Benefit,Expenses,FALSE,
61100090,Maternity Benefit,Expenses,FALSE,
61100100,Pph 21 Benefit,Expenses,FALSE,
62110010,Free Gift,Expenses,FALSE,
62110020,Event,Expenses,FALSE,
62110030,Advertising,Expenses,FALSE,
62110040,Shipping Merchandise,Expenses,FALSE,
63110010,Drinking Water,Expenses,FALSE,
63110020,Exercise Necessities,Expenses,FALSE,
63110030,Monthly Fee,Expenses,FALSE,
63110040,Donation,Expenses,FALSE,
63110050,Internet,Expenses,FALSE,
63110060,Phone,Expenses,FALSE,
63110070,Prepaid Phone Bills,Expenses,FALSE,
63110080,Electricity,Expenses,FALSE,
63110090,Water (PDAM),Expenses,FALSE,
63110100,Research & Development,Expenses,FALSE,
63110110,Kitchen Necessities,Expenses,FALSE,
63110120,Office Equipment,Expenses,FALSE,
63110130,First Aid Kit,Expenses,FALSE,
63110140,Other Necessities,Expenses,FALSE,
63110150,K3 (Fire Extinguisher),Expenses,FALSE,
63110160,Cleaning Equipment,Expenses,FALSE,
63110180,Owner Necessities,Expenses,FALSE,
64110010,Office Stationery,Expenses,FALSE,
64110020,Post Necessities,Expenses,FALSE,
64110030,Jilid & Photocopy,Expenses,FALSE,
64110040,Job Recruitment Advertisement,Expenses,FALSE,
64110050,Stamp,Expenses,FALSE,
65110010,Licensing Fees,Expenses,FALSE,
65110020,Bank Administration Fees,Expenses,FALSE,
65110030,Consultant Fees,Expenses,FALSE,
65110040,Rental Costs,Expenses,FALSE,
65110060,Building Maintenance Costs,Expenses,FALSE,
65110070,"Electricity, Telephone, and Internet Installation Maintenance Costs",Expenses,FALSE,
65110080,Taxes,Expenses,FALSE,
65110090,Guest Accomodation,Expenses,FALSE,
65110100,Asset Maintenance Costs,Expenses,FALSE,
65110110,Shipping Costs,Expenses,FALSE,
66110010,Vehicle Fuel,Expenses,FALSE,
66110020,Vehicle Service,Expenses,FALSE,
66110030,Vehicle Parking & Toll Fee,Expenses,FALSE,
66110040,Vehicle Taxes,Expenses,FALSE,
66110050,Vehicle Insurance,Expenses,FALSE,
67100010,Land,Expenses,FALSE,
67100020,Office Building,Expenses,FALSE,
67100030,Vehicle,Expenses,FALSE,
67100040,Office Supplies,Expenses,FALSE,
67100050,Software,Expenses,FALSE,
67100060,Office Furniture,Expenses,FALSE,
69000000,Other Expenses,Expenses,FALSE,
81100010,Interest Income,Other Income,FALSE,
81100020,Deposit Income,Other Income,FALSE,
81100030,Foreign Exchange Gain,Other Income,FALSE,
81100040,Other Income,Other Income,FALSE,
81100090,Gain on Sale of Fixed Assets,Other Income,FALSE,
91100010,Interest Expense,Expenses,FALSE,
91100020,Bank Administration Expense,Expenses,FALSE,
91100030,Foreign Exchange Loss,Expenses,FALSE,
91100090,Loss on Sale of Fixed Assets,Expenses,FALSE,
99900001,Cash Difference Loss,Expenses,FALSE,
99900002,Cash Difference Gain,Income,FALSE,
999999,Undistributed Profits/Losses,Current Year Earnings,FALSE,
No preview for this file type
import csv
import glob
import os
import sys
import logging
_logger = logging.getLogger(__name__)
NOUPDATE = 1
BOOLEAN = ('True', 'False')
ERP_HEADER = """
<?xml version="1.0"?>
<odoo>
<data noupdate="%s">"""
ERP_FOOTER = """
</data>
</odoo>
"""
FILES_WITH_UPDATE = ('product.product.csv')
def convert_relationnal_field2xml(tag, value):
mytag = tag
for elm in ['/ids', '/id', ':id']:
mytag = mytag.replace(elm, '')
if tag[-6:] == 'ids/id':
# many2many
line = '"%s" eval="[(6, 0, [%s])]"' % (mytag, value)
else:
# many2one
line = '"%s" ref="%s"' % (mytag, value)
return line
def proses(path, name):
file_name = os.path.join(path, name)
for csv_file in glob.glob(file_name):
no_update = NOUPDATE
if csv_file in FILES_WITH_UPDATE:
no_update = 0
xml_file = csv_file.replace('.', '_').replace('_csv', '_data.xml')
xml_data = open(xml_file, 'w')
xml_data.write(ERP_HEADER % NOUPDATE + "\n\n\n")
with open(csv_file, 'r') as csv_data:
reader = csv.DictReader(csv_data)
print(f"reader {reader}")
model, ext = os.path.splitext(csv_file)
for row in reader:
xml_data.write(f' <record id="{row["id"]}" model={model}>\n')
for key in row:
if key == "id":
continue
begin = ''
if '/' in key or ':' in key:
xml_suffix = convert_relationnal_field2xml(key, row[key])
line = f' <field name={xml_suffix}/>\n'
else:
# basic fields
value = row[key]
line = f" <field name='{key}'>{value}</field>\n"
xml_data.write(line)
xml_data.write(f" </record>\n")
xml_data.write(ERP_FOOTER)
xml_data.close()
def usage(argv):
print(f"{__name__} file_name")
def main(argv=sys.argv):
if len(argv) != 2:
return usage(argv)
file_name = argv[1]
name, ext = os.path.splitext(file_name)
if not ext or ext != '.csv':
print(f"File {file_name} bukan csv")
sys.exit()
path = os.path.dirname(file_name)
name = os.path.basename(file_name)
if not os.path.exists(path):
print(f"Path {path} tidak ditemukan")
sys.exit()
if name.find('*') < 0:
if not os.path.exists(file_name):
print(f"Filename {name} tidak ditemukan")
sys.exit()
proses(path, name)
if __name__ == '__main__':
print("Start Module")
main(sys.argv)
......@@ -22,6 +22,9 @@ RI Goverment Dashboard
'views/region_tax_plan_sum.xml',
'views/region_tax_actual.xml',
'views/region_tax_actual_sum.xml',
'views/dw_objek.xml',
'views/dw_invoice.xml',
'views/dw_payment.xml',
'views/menus.xml',
'data/portal.xml',
'views/portal_templates.xml',
......
......@@ -85,18 +85,45 @@ class IdgBoardWebsite(Website):
)
province_domain = ['&', ('level', '=', 6),
('district_id', '=', None)]
province_taxs = IdgTaxSum.search(
province_domain,
limit=self._items_per_page,
offset=pager['offset']
)
district_domain = ['&', ('level', '=', 6),
('district_id', '!=', None)]
district_taxs = IdgTaxSum.search(
district_domain,
limit=self._items_per_page,
offset=pager['offset']
)
# search(
# province_domain,
# limit=self._items_per_page,
# offset=pager['offset']
# )
sql = """
SELECT s.account_group_id, ag.name, ag.code_prefix_start as code,
sum(s.amount) amount, sum(s.qty) as qty
FROM idg_region_tax_potency_sum s
JOIN account_group ag ON s.account_group_id=ag.id
WHERE s.level=6 AND s.district_id is Null and year=2021
GROUP BY s.account_group_id, ag.name, ag.code_prefix_start
"""
request.env.cr.execute(sql)
province_taxs = request.env.cr.dictfetchall()
# print(province_taxs )
# province_taxs = IdgTaxSum.read_group(domain=province_domain,
# fields=['account_group_id', 'amount', 'qty'],
# groupby=['account_group_id'])
#
# district_domain = ['&', ('level', '=', 6),
# ('district_id', '!=', None)]
# district_taxs = IdgTaxSum.search(
# district_domain,
# limit=self._items_per_page,
# offset=pager['offset']
# )
sql = """
SELECT s.account_group_id, ag.name, ag.code_prefix_start as code,
sum(s.amount) amount, sum(s.qty) as qty
FROM idg_region_tax_potency_sum s
JOIN account_group ag ON s.account_group_id=ag.id
WHERE s.level=6 AND s.district_id is not Null and year=2021
GROUP BY s.account_group_id, ag.name, ag.code_prefix_start
"""
request.env.cr.execute(sql)
district_taxs = request.env.cr.dictfetchall()
values.update({
'province_taxs': province_taxs,
......
from . import idg_region_tax_plan
from . import idg_region_tax_potency
from . import idg_region_tax_actual
from . import data_warehouse
from odoo import fields, models, api
class IdgrDwObjekPajak(models.Model):
_name = 'idgr.dw.objek'
_inherit = 'portal.mixin'
jns_pemda = fields.Selection(
selection=[("kota", "Kota"),
("kotif", "Kota Administratif"),
("kab", "Kabupaten"),
("kabtif", "Kabupaten Administratif"),
("prov", "Provinsi"),
("provtif", "Provinsi Administratif"),
],
string="Jns. Pemda", size=16)
kd_pemda = fields.Char(string="Kode Pemda", size=8)
nm_pemda = fields.Char(string="Nama Pemda", size=128)
kd_rek_rinci = fields.Char(string="Kode Rekening", size=16)
nm_rek_rinci = fields.Char(string="Nama Rekening", size=128)
nop = fields.Char(string="NOPD", size=32)
nm_op = fields.Char(string="Nama OP", size=128)
alamat_op = fields.Char(string="Alamat OP", size=128)
alamat_op2 = fields.Char(string="Alamat OP", size=128)
kelurahan_op = fields.Char(string="Kelurahan OP", size=64)
kecamatan_op = fields.Char(string="Kecamatan OP", size=64)
kota_op = fields.Char(string="Kota OP", size=64)
propinsi_op = fields.Char(string="Provinsi OP", size=64)
status = fields.Integer(string="Status OP", default=1)
kd_wp = fields.Char(string="Identitas WP", size=32)
nm_wp = fields.Char(string="Nama WP", size=128)
npwpd = fields.Char(string="NPWPD WP", size=32)
alamat_wp = fields.Char(string="Alamat WP", size=128)
alamat_wp2 = fields.Char(string="Alamat WP", size=128)
kelurahan_wp = fields.Char(string="Kelurahan WP", size=64)
kecamatan_wp = fields.Char(string="Kecamatan WP", size=64)
kota_wp = fields.Char(string="Kota WP", size=64)
propinsi_wp = fields.Char(string="Provinsi WP", size=64)
njop = fields.Integer(string="NJOP/Omset")
tarif = fields.Integer(string="Tarif")
tgl_kukuh = fields.Date(string="Tgl. Kukuh")
class IdgrDwInvoice(models.Model):
_name = "idgr.dw.invoice"
jns_pemda = fields.Selection(
selection=[("kota", "Kota"),
("kotif", "Kota Administratif"),
("kab", "Kabupaten"),
("kabtif", "Kabupaten Administratif"),
("prov", "Provinsi"),
("provtif", "Provinsi Administratif"),
],
string="Jns. Pemda", size=16)
kd_pemda = fields.Char(string="Kode Pemda", size=8)
nm_pemda = fields.Char(string="Nama Pemda", size=128)
kd_rek_rinci = fields.Char(string="Kode Rek", size=16)
nm_rek_rinci = fields.Char(string="Nama Rek", size=128)
# kelompok = fields.Char(string="Name", size=32)
nop = fields.Char(string="NOPD", size=32)
# nm_op = fields.Char(string="Nama Objek")
# alamat_op = fields.Char(string="Alamat Objek", size=128)
# alamat_op2 = fields.Char(string="Alamat Objek2", size=128)
# kelurahan_op = fields.Char(string="Kelurahan Objek", size=64)
# kecamatan_op = fields.Char(string="Kecamatan Objek", size=64)
# kota_op = fields.Char(string="Kota Objek", size=64)
# propinsi_op = fields.Char(string="Provinsi Objek", size=64)
# kd_wp = fields.Char(string="Identitas WP", size=32)
# nm_wp = fields.Char(string="Nama WP", size=128)
# npwpd = fields.Char(string="NPWPD", size=32)
# alamat_wp = fields.Char(string="Alamat WP", size=128)
# alamat_wp2 = fields.Char(string="Alamat WP", size=128)
# kelurahan_wp = fields.Char(string="Kelurahan WP", size=64)
# kecamatan_wp = fields.Char(string="Kecamatan WP", size=64)
# kota_wp = fields.Char(string="Kota WP", size=64)
# propinsi_wp = fields.Char(string="Provinsi WP", size=64)
njop = fields.Integer(string="NJOP/Omset")
tarif = fields.Float(string="Tarif")
pokok = fields.Integer(string="Pokok")
denda = fields.Integer(string="Denda")
periode_awal = fields.Date(string="Periode Awal")
periode_akhir = fields.Date(string="Periode Akhir")
tahun_pajak = fields.Integer(string="Thn. Pajak")
bulan_pajak = fields.Integer(string="Bln. Pajak")
no_bayar = fields.Char(string="Nomor Bayar", size=128)
no_tetap = fields.Char(string="Nomor", size=128)
tgl_tetap = fields.Date(string="Tanggal Tetap")
jth_tempo = fields.Date(string="Jth. Tempo")
jns_tagihan = fields.Selection(
selection=[
('sspd', "SSPD"),
('sptpd', "SPTPD"),
('skpd', 'SKPD'),
('kb', 'SKPD-KB'),
('kbt', 'SKPD-KBT'),
('stpd', 'STPD'),
('lb', 'SKPD-LB'),
])
tahun_tetap = fields.Integer(compute="_compute_tgl_tetap", string="Thn. Tetap", store=True)
bulan_tetap = fields.Integer(compute="_compute_tgl_tetap", string="Bln. Tetap", store=True)
hari_tetap = fields.Integer(compute="_compute_tgl_tetap", string="Tgl. Tetap", store=True)
nm_op = fields.Char(compute="_compute_objek", string="Nama OP", )
alamat_op = fields.Char(compute="_compute_objek", string="Alamat OP", )
alamat_op2 = fields.Char(compute="_compute_objek", string="Alamat OP", )
kelurahan_op = fields.Char(compute="_compute_objek", string="Kelurahan OP", )
kecamatan_op = fields.Char(compute="_compute_objek", string="Kecamatan OP", )
kota_op = fields.Char(compute="_compute_objek", string="Kota OP", )
propinsi_op = fields.Char(compute="_compute_objek", string="Provinsi OP", )
kd_wp = fields.Char(compute="_compute_objek", string="Identitas WP", )
nm_wp = fields.Char(compute="_compute_objek", string="Nama WP", )
npwpd = fields.Char(compute="_compute_objek", string="NPWPD WP", )
alamat_wp = fields.Char(compute="_compute_objek", string="Alamat WP", )
alamat_wp2 = fields.Char(compute="_compute_objek", string="Alamat WP", )
kelurahan_wp = fields.Char(compute="_compute_objek", string="Kelurahan WP", )
kecamatan_wp = fields.Char(compute="_compute_objek", string="Kecamatan WP", )
kota_wp = fields.Char(compute="_compute_objek", string="Kota WP", )
propinsi_wp = fields.Char(compute="_compute_objek", string="Provinsi WP", )
tgl_kukuh = fields.Date(compute="_compute_objek", string="Tgl. Pengukuhan", )
def _compute_tgl_tetap(self):
for row in self:
row.tahun_tetap = row.tgl_tetap.year
row.bulan_tetap = row.tgl_tetap.month
row.hari_tetap = row.tgl_tetap.day
def _calculte_op(self):
for row in self:
pass
class IdgrDwPayment(models.Model):
_name = "idgr.dw.payment"
jns_pemda = fields.Selection(
selection=[("kota", "Kota"),
("kotif", "Kota Administratif"),
("kab", "Kabupaten"),
("kabtif", "Kabupaten Administratif"),
("prov", "Provinsi"),
("provtif", "Provinsi Administratif"),
],
string="Jns. Pemda", size=16)
kd_pemda = fields.Char(string="Kode Pemda", size=8)
nm_pemda = fields.Char(string="Nama Pemda", size=128)
kd_rek_rinci = fields.Char(string="Kode Rek", size=16)
no_tagihan = fields.Char(string="No. Tagihan", size=128)
tgl_bayar = fields.Date(string="Tgl. Bayar")
denda = fields.Integer(string="Denda")
jumlah = fields.Integer(string="Bayar")
nop = fields.Char(compute="_compute_invoice", string="NOP", )
nm_rek_rinci = fields.Char(compute="_compute_invoice", string="Nama Rekening", )
njop = fields.Integer(compute="_compute_invoice", string="NJOP/Omset")
tarif = fields.Float(compute="_compute_invoice", string="Tarif")
pokok_inv = fields.Integer(compute="_compute_invoice", string="Pokok")
denda_inv = fields.Integer(compute="_compute_invoice", string="Denda")
periode_awal = fields.Date(compute="_compute_invoice", string="Periode Awal")
periode_akhir = fields.Date(compute="_compute_invoice", string="Periode Akhir")
tahun_pajak = fields.Integer(compute="_compute_invoice", string="Thn. Pajak")
bulan_pajak = fields.Integer(compute="_compute_invoice", string="Bln. Pajak")
no_bayar = fields.Char(compute="_compute_invoice", string="Nomor Bayar", size=128)
no_tetap = fields.Char(compute="_compute_invoice", string="Nomor", size=128)
tgl_tetap = fields.Date(compute="_compute_invoice", string="Tanggal Tetap")
jth_tempo = fields.Date(compute="_compute_invoice", string="Jth. Tempo")
jns_tagihan = fields.Char(compute="_compute_invoice", string="Jns. Tagihan")
nm_op = fields.Char(compute="_compute_objek", string="Nama OP", )
alamat_op = fields.Char(compute="_compute_objek", string="Alamat OP", )
alamat_op2 = fields.Char(compute="_compute_objek", string="Alamat OP", )
kelurahan_op = fields.Char(compute="_compute_objek", string="Kelurahan OP", )
kecamatan_op = fields.Char(compute="_compute_objek", string="Kecamatan OP", )
kota_op = fields.Char(compute="_compute_objek", string="Kota OP", )
propinsi_op = fields.Char(compute="_compute_objek", string="Provinsi OP", )
kd_wp = fields.Char(compute="_compute_objek", string="Identitas WP", )
nm_wp = fields.Char(compute="_compute_objek", string="Nama WP", )
npwpd = fields.Char(compute="_compute_objek", string="NPWPD WP", )
alamat_wp = fields.Char(compute="_compute_objek", string="Alamat WP", )
alamat_wp2 = fields.Char(compute="_compute_objek", string="Alamat WP", )
kelurahan_wp = fields.Char(compute="_compute_objek", string="Kelurahan WP", )
kecamatan_wp = fields.Char(compute="_compute_objek", string="Kecamatan WP", )
kota_wp = fields.Char(compute="_compute_objek", string="Kota WP", )
propinsi_wp = fields.Char(compute="_compute_objek", string="Provinsi WP", )
def _compute_objek(self):
for row in self:
pass
def _compute_invoice(self):
for row in self:
pass
......@@ -6,3 +6,6 @@
"access_idg_region_tax_plan_sum_admin","access.idg.region.tax.plan.sum.admin","model_idg_region_tax_plan_sum","base.group_system",1,1,1,1
"access_idg_region_tax_actual_admin","access.idg.region.tax.actual.admin","model_idg_region_tax_actual","base.group_system",1,1,1,1
"access_idg_region_tax_actual_sum_admin","access.idg.region.tax.actual.sum.admin","model_idg_region_tax_actual_sum","base.group_system",1,1,1,1
"access_idgr_dw_objek_admin","access.idg.region.tax.actual.sum.admin","model_idgr_dw_objek","base.group_system",1,1,1,1
"access_idgr_dw_invoice_admin","access.idg.region.tax.actual.sum.admin","model_idgr_dw_invoice","base.group_system",1,1,1,1
"access_idgr_dw_payment_admin","access.idg.region.tax.actual.sum.admin","model_idgr_dw_payment","base.group_system",1,1,1,1
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<record id="idgr_dw_invoice_search" model="ir.ui.view">
<field name="name">idgr.dw.invoice.search</field>
<field name="model">idgr.dw.invoice</field>
<field name="arch" type="xml">
<search string="Area">
<field name="kd_pemda"
string="Kode"/>
<field name="nm_pemda"
string="Nama"/>
<field name="kd_rek_rinci"
string="Kode Rekening"/>
<field name="nm_rek_rinci"
string="Nama Rekening"/>
<group expand="0" string="Group By">
<filter string="Kode" name="kode" domain="" context="{'group_by':'kd_pemda'}"/>
<filter string="Nama" name="nama" domain="" context="{'group_by':'nm_pemda'}"/>
<filter string="Rekening" name="rekening" domain="" context="{'group_by':'kd_rek_rinci'}"/>
</group>
</search>
</field>
</record>
<record id="idgr_dw_invoice_tree" model="ir.ui.view">
<field name="name">idgr.dw.invoice.tree</field>
<field name="model">idgr.dw.invoice</field>
<field name="arch" type="xml">
<tree string="Region Tax Potency" sample="1" create="1" delete="1" multi_edit="0">
<field name="kd_pemda"/>
<field name="nm_pemda"/>
<field name="nop"/>
<field name="njop"/>
<field name="tarif"/>
<field name="pokok"/>
<field name="denda"/>
<field name="tgl_tetap"/>
<field name="jth_tempo"/>
<field name="tahun_pajak"/>
<field name="bulan_pajak"/>
</tree>
</field>
</record>
<record id="idgr_dw_invoice_form" model="ir.ui.view">
<field name="name">idgr.dw.invoice.form</field>
<field name="model">idgr.dw.invoice</field>
<field name="arch" type="xml">
<form string="Region Tax Potency" sample="1">
<sheet>
<group>
<field name="jns_pemda"/>
<field name="nm_pemda"/>
<field name="kd_pemda"/>
<field name="kd_rek_rinci"/>
<field name="nm_rek_rinci"/>
<field name="jns_tagihan"/>
<field name="no_bayar"/>
<field name="no_tetap"/>
<field name="tgl_tetap"/>
<field name="nop"/>
<field name="tahun_pajak"/>
<field name="bulan_pajak"/>
<field name="njop"/>
<field name="tarif"/>
<field name="pokok"/>
<field name="denda"/>
<field name="periode_awal"/>
<field name="periode_akhir"/>
<field name="jth_tempo"/>
</group>
<notebook>
<page name="invoice_pajak">
<group>
<field name="nm_op"/>
<field name="alamat_op"/>
<field name="alamat_op2"/>
<field name="kelurahan_op"/>
<field name="kecamatan_op"/>
<field name="kota_op"/>
<field name="propinsi_op"/>
</group>
</page>
<page name="wajib_pajak">
<group>
<field name="kd_wp"/>
<field name="nm_wp"/>
<field name="npwpd"/>
<field name="alamat_wp"/>
<field name="alamat_wp2"/>
<field name="kelurahan_wp"/>
<field name="kecamatan_wp"/>
<field name="kota_wp"/>
<field name="propinsi_wp"/>
<field name="tgl_kukuh"/>
</group>
</page>
</notebook>
</sheet>
</form>
</field>
</record>
<record id="action_idgr_dw_invoice" model="ir.actions.act_window">
<field name="name">DW Region Tax Object</field>
<field name="res_model">idgr.dw.invoice</field>
<field name="view_mode">tree,form,graph</field>
<field name="view_id" ref="idgr_dw_invoice_tree"/>
<field name="search_view_id" ref="idgr_dw_invoice_search"/>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
Objek Pajak
</p>
</field>
</record>
</data>
</odoo>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<record id="idgr_dw_objek_search" model="ir.ui.view">
<field name="name">idgr.dw.objek.search</field>
<field name="model">idgr.dw.objek</field>
<field name="arch" type="xml">
<search string="Area">
<field name="kd_pemda"
string="Kode"/>
<field name="nm_pemda"
string="Nama"/>
<field name="kd_rek_rinci"
string="Kode Rekening"/>
<field name="nm_rek_rinci"
string="Nama Rekening"/>
<group expand="0" string="Group By">
<filter string="Kode" name="kode" domain="" context="{'group_by':'kd_pemda'}"/>
<filter string="Nama" name="nama" domain="" context="{'group_by':'nm_pemda'}"/>
<filter string="Rekening" name="rekening" domain="" context="{'group_by':'kd_rek_rinci'}"/>
</group>
</search>
</field>
</record>
<record id="idgr_dw_objek_tree" model="ir.ui.view">
<field name="name">idgr.dw.objek.tree</field>
<field name="model">idgr.dw.objek</field>
<field name="arch" type="xml">
<tree string="Region Tax Potency" sample="1" create="1" delete="1" multi_edit="0">
<field name="kd_pemda"/>
<field name="nm_pemda"/>
<field name="nop"/>
<field name="npwpd"/>
<field name="njop"/>
<field name="tarif"/>
</tree>
</field>
</record>
<record id="idgr_dw_objek_form" model="ir.ui.view">
<field name="name">idgr.dw.objek.form</field>
<field name="model">idgr.dw.objek</field>
<field name="arch" type="xml">
<form string="Region Tax Potency" sample="1">
<sheet>
<group>
<group>
<label for="jns_pemda" string="Pemda"/>
<div>
<field name="jns_pemda" class="oe_inline"/>
<field name="kd_pemda"/>
</div>
<field name="nm_pemda"/>
<label for="kd_rek_rinci" string="Rekening"/>
<div>
<field name="kd_rek_rinci" class="oe_inline"/>
<field name="nm_rek_rinci" class="oe_inline"/>
</div>
<field name="nop"/>
<field name="njop"/>
<field name="tarif"/>
<field name="tgl_kukuh"/>
</group>
</group>
<notebook>
<page name="objek_pajak" string="Objek Pajak">
<group>
<field name="nm_op" placeholder="Nama OP..."/>
<label for="alamat_op" string="Alamat OP"/>
<div class="o_address_format">
<field name="alamat_op" placeholder="Alamat..."/>
<field name="alamat_op2" placeholder="Alamat2..."/>
<field name="kelurahan_op" placeholder="Kelurahan..."/>
<field name="kecamatan_op" placeholder="Kecamatan..."/>
<field name="kota_op" placeholder="Kota..."/>
<field name="propinsi_op" placeholder="Provinsi..."/>
</div>
</group>
</page>
<page name="wajib_pajak" string="Wajib Pajak">
<group>
<field name="kd_wp"/>
<field name="nm_wp"/>
<field name="npwpd"/>
<label for="alamat_op" string="Alamat OP"/>
<div class="o_address_format">
<field name="alamat_wp" placeholder="Alamat..."/>
<field name="alamat_wp2" placeholder="Alamat2..."/>
<field name="kelurahan_wp" placeholder="Kelurahan..."/>
<field name="kecamatan_wp" placeholder="Kecamatan..."/>
<field name="kota_wp" placeholder="Kota..."/>
<field name="propinsi_wp" placeholder="Provinsi..."/>
</div>
<field name="status" invisible="1"/>
</group>
</page>
</notebook>
</sheet>
</form>
</field>
</record>
<record id="action_idgr_dw_objek" model="ir.actions.act_window">
<field name="name">DW Region Tax Object</field>
<field name="res_model">idgr.dw.objek</field>
<field name="view_mode">tree,form,graph</field>
<field name="view_id" ref="idgr_dw_objek_tree"/>
<field name="search_view_id" ref="idgr_dw_objek_search"/>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
Objek Pajak
</p>
</field>
</record>
</data>
</odoo>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<record id="idgr_dw_payment_search" model="ir.ui.view">
<field name="name">idgr.dw.payment.search</field>
<field name="model">idgr.dw.payment</field>
<field name="arch" type="xml">
<search string="Area">
<field name="kd_pemda"
string="Kode"/>
<field name="nm_pemda"
string="Nama"/>
<field name="kd_rek_rinci"
string="Kode Rekening"/>
<field name="nm_rek_rinci"
string="Nama Rekening"/>
<group expand="0" string="Group By">
<filter string="Kode" name="kode" domain="" context="{'group_by':'kd_pemda'}"/>
<filter string="Nama" name="nama" domain="" context="{'group_by':'nm_pemda'}"/>
<filter string="Rekening" name="rekening" domain="" context="{'group_by':'kd_rek_rinci'}"/>
</group>
</search>
</field>
</record>
<record id="idgr_dw_payment_tree" model="ir.ui.view">
<field name="name">idgr.dw.payment.tree</field>
<field name="model">idgr.dw.payment</field>
<field name="arch" type="xml">
<tree string="Region Tax Potency" sample="1" create="1" delete="1" multi_edit="0">
<field name="kd_pemda"/>
<field name="nm_pemda"/>
<field name="no_tagihan"/>
<field name="denda"/>
<field name="jumlah"/>
<field name="tgl_bayar"/>
</tree>
</field>
</record>
<record id="idgr_dw_payment_form" model="ir.ui.view">
<field name="name">idgr.dw.payment.form</field>
<field name="model">idgr.dw.payment</field>
<field name="arch" type="xml">
<form string="Region Tax Potency" sample="1">
<sheet>
<group>
<field name="jns_pemda"/>
<field name="nm_pemda"/>
<field name="kd_pemda"/>
<field name="kd_rek_rinci"/>
<field name="nm_rek_rinci"/>
<field name="jns_tagihan"/>
<field name="no_bayar"/>
<field name="no_tetap"/>
<field name="tgl_tetap"/>
<field name="nop"/>
<field name="tahun_pajak"/>
<field name="bulan_pajak"/>
<field name="njop"/>
<field name="tarif"/>
<!-- <field name="pokok"/>-->
<!-- <field name="denda"/>-->
<field name="periode_awal"/>
<field name="periode_akhir"/>
<field name="jth_tempo"/>
</group>
<notebook>
<page name="payment_pajak">
<group>
<field name="nm_op"/>
<field name="alamat_op"/>
<field name="alamat_op2"/>
<field name="kelurahan_op"/>
<field name="kecamatan_op"/>
<field name="kota_op"/>
<field name="propinsi_op"/>
</group>
</page>
<page name="wajib_pajak">
<group>
<field name="kd_wp"/>
<field name="nm_wp"/>
<field name="npwpd"/>
<field name="alamat_wp"/>
<field name="alamat_wp2"/>
<field name="kelurahan_wp"/>
<field name="kecamatan_wp"/>
<field name="kota_wp"/>
<field name="propinsi_wp"/>
<!-- <field name="njop"/>-->
<!-- <field name="tarif"/>-->
<!-- <field name="pokok"/>-->
<!-- <field name="denda"/>-->
<!-- <field name="tgl_kukuh"/>-->
<!-- <field name="status"/>-->
</group>
</page>
</notebook>
</sheet>
</form>
</field>
</record>
<record id="action_idgr_dw_payment" model="ir.actions.act_window">
<field name="name">DW Region Tax Object</field>
<field name="res_model">idgr.dw.payment</field>
<field name="view_mode">tree,form,graph</field>
<field name="view_id" ref="idgr_dw_payment_tree"/>
<field name="search_view_id" ref="idgr_dw_payment_search"/>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
Objek Pajak
</p>
</field>
</record>
</data>
</odoo>
\ No newline at end of file
......@@ -46,7 +46,7 @@
<menuitem id="transaksi_idgd_menu"
name="Transaksi"
parent="idgd_menu_root"
sequence="6"/>
sequence="5"/>
<menuitem id="potency_idgd_menu"
name="Region Tax Potency"
parent="transaksi_idgd_menu"
......@@ -79,4 +79,26 @@
action="action_idg_region_tax_actual_sum"
sequence="6"/>
<menuitem id="region_dw_idgd_menu"
name="Data Warehouse"
parent="idgd_menu_root"
sequence="6"/>
<menuitem id="dw_objek_idgd_menu"
name="Objek Pajak"
parent="region_dw_idgd_menu"
action="action_idgr_dw_objek"
sequence="1"/>
<menuitem id="dw_invoice_idgd_menu"
name="Tagihan/Ketetapan"
parent="region_dw_idgd_menu"
action="action_idgr_dw_invoice"
sequence="2"/>
<menuitem id="dw_payment_idgd_menu"
name="Pembayaran"
parent="region_dw_idgd_menu"
action="action_idgr_dw_payment"
sequence="3"/>
</odoo>
......@@ -10,7 +10,8 @@
<t t-call="portal.portal_table">
<thead>
<tr class="active">
<th class="text-left">Tax Category</th>
<th class="text-left">Code</th>
<th class="text-left">Category</th>
<th class="text-right">Qty</th>
<th class="text-right">Amount</th>
</tr>
......@@ -19,15 +20,17 @@
<t t-foreach="province_taxs" t-as="tax">
<tr>
<td>
<a t-att-href="tax.get_portal_url()">
<t t-esc="tax.account_group_id.name"/>
</a>
<t t-esc="tax['code']"/>
</td>
<td>
<!-- <a t-att-href="tax.get_portal_url()">-->
<t t-esc="tax['name']"/>
</td>
<td class="text-right">
<span t-field="tax.qty"/>
<span t-esc="tax['qty']"/>
</td>
<td class="text-right">
<span t-field="tax.amount"/>
<span t-esc="tax['amount']"/>
</td>
</tr>
</t>
......@@ -39,7 +42,8 @@
<t t-call="portal.portal_table">
<thead>
<tr class="active">
<th class="text-left">Tax Category</th>
<th class="text-left">Code</th>
<th class="text-left">Category</th>
<th class="text-right">Qty</th>
<th class="text-right">Amount</th>
</tr>
......@@ -48,15 +52,20 @@
<t t-foreach="district_taxs" t-as="tax">
<tr>
<td>
<a t-att-href="tax.get_portal_url()">
<t t-esc="tax.account_group_id.name"/>
</a>
<!-- <a t-att-href="tax.get_portal_url()">-->
<t t-esc="tax['code']"/>
<!-- </a>-->
</td>
<td>
<!-- <a t-att-href="tax.get_portal_url()">-->
<t t-esc="tax['name']"/>
<!-- </a>-->
</td>
<td class="text-right">
<span t-field="tax.qty"/>
<span t-esc="tax['qty']"/>
</td>
<td class="text-right">
<span t-field="tax.amount"/>
<span t-esc="tax['amount']"/>
</td>
</tr>
</t>
......
......@@ -17,7 +17,6 @@
</search>
</field>
</record>
<record id="idg_region_tax_potency_tree" model="ir.ui.view">
<field name="name">idg.region.tax.potency.tree</field>
<field name="model">idg.region.tax.potency</field>
......@@ -32,7 +31,6 @@
</tree>
</field>
</record>
<record id="idg_region_tax_potency_form" model="ir.ui.view">
<field name="name">idg.region.tax.potency.form</field>
<field name="model">idg.region.tax.potency</field>
......@@ -45,7 +43,6 @@
<h2>
<field name="district_id"/>
</h2>
<group>
<field name="country_id" invisible="1"/>
<field name="account_id"/>
......@@ -57,7 +54,6 @@
</form>
</field>
</record>
<record id="action_idg_region_tax_potency" model="ir.actions.act_window">
<field name="name">Region Tax Potency</field>
<field name="res_model">idg.region.tax.potency</field>
......@@ -71,6 +67,5 @@
</p>
</field>
</record>
</data>
</odoo>
\ No newline at end of file
......@@ -15,8 +15,8 @@ class BphtbSales(models.Model):
_name = 'bphtb.sales'
_description = 'Transaksi BPHTB'
_inherit = ['portal.mixin', 'mail.thread', 'mail.activity.mixin', 'sequence.mixin']
name = fields.Char(string='Number', copy=False, compute='_compute_name', readonly=False, store=True, index=True,
tracking=True)
name = fields.Char(string='Number', copy=False, compute='_compute_name', readonly=False,
store=True, index=True, tracking=True)
ref = fields.Char(string='Reference', copy=False, tracking=True)
#
# rate = fields.Float(required=True)
......
E-Office Letter Management
-----
#Fungsi
1. Mengelola surat masuk/surat keluar
2. Mengelola Penomoran Surat
#User Type
1. Generic User
2. Letter User
3. Letter Administrator
#Status Surat
1. Draft
2. Pending (Waiting for Approval)
3. Approved (Di approve semua user required)
4. Refused (Dikembalikan kepada pembuat)
* Salah satu required approval melakukan refuse/penolakan
* Bisa diubah jadi draft oleh pembuat
5. Canceled
* Salah satu required approval melakukan cancel data
# Surat Masuk
1. "Letter User" Membuat surat masuk
2. Sistem melakukan auto routing ke Top Manager
3. Setiap Manager dapat menambahkan routing ke staff di bawahnya
# Surat Keluar
1. Setiap User berhak membuat surat keluar
2. System melakukan otomasi routing ke manager user
3. Manager melakukan proses autorisasi
4. "No Surat" diinput oleh "Letter User" jika semua manager yang wajib sudah approved
# Restriction
1. Generic user
1. Hanya bisa membaca data milik sendiri
2. Melakukan approval untuk surat yang diterima
3. Menambahkan pegawai untuk approval
4. Tidak bisa menghapus surat yang sudah dibuat
5. Tidak bisa menghapus Approval default (required)
6. Tidak bisa mengisi code surat keluar
2. Letter User
1. Input Data Code Surat Keluar
3. Letter Administrator
1. Membaca semua record surat
2. Menghapus record yang belum approval
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import controllers
from . import models
from . import wizard
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
{
'name': 'E-OFFICE LETTER',
'version': '0.1',
'summary': 'Letter Office Management',
'sequence': 11,
'description': """
E-OFFICE
=================
Memudahkan dalam mengelola surat menyurat
""",
'category': 'IDG OFFICE',
'website': 'https://opensipkd.com',
'images': [],
'depends': ['mail','hr'],
'data': [
'security/account_security.xml',
'security/ir.model.access.csv',
'security/ir_rule.xml',
'views/menus.xml',
'views/category.xml',
'views/incoming_letter.xml',
'views/task_letter.xml',
],
'demo': [
# 'security/ir_rule.xml',
# 'data/res_user.xml',
],
'qweb': [],
'installable': True,
'application': True,
'auto_install': False,
'license': 'LGPL-3',
'module': 'idg-letter'
}
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import onboarding
from . import portal
from odoo import http
from odoo.http import request
class OnboardingController(http.Controller):
@http.route('/pad/pad_invoice_onboarding', auth='user', type='json')
def pad_invoice_onboarding(self):
""" Returns the `banner` for the pad invoice onboarding panel.
It can be empty if the user has closed it or if he doesn't have
the permission to see it. """
company = request.env.company
if not request.env.is_admin() or \
company.pad_invoice_onboarding_state == 'closed':
return {}
return {
'html': request.env.ref('pad.pad_invoice_onboarding_panel')._render({
'company': company,
'state': company.get_and_update_pad_invoice_onboarding_state()
})
}
@http.route('/pad/pad_dashboard_onboarding', auth='user', type='json')
def pad_dashboard_onboarding(self):
""" Returns the `banner` for the pad dashboard onboarding panel.
It can be empty if the user has closed it or if he doesn't have
the permission to see it. """
company = request.env.company
if not request.env.is_admin() or \
company.pad_dashboard_onboarding_state == 'closed':
return {}
return {
'html': request.env.ref('pad.pad_dashboard_onboarding_panel')._render({
'company': company,
'state': company.get_and_update_pad_dashboard_onboarding_state()
})
}
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import base64
from collections import OrderedDict
from datetime import datetime
from odoo import http
from odoo.exceptions import AccessError, MissingError
from odoo.http import request, Response
from odoo.tools import image_process
from odoo.tools.translate import _
from odoo.addons.portal.controllers.portal import (
get_records_pager, pager as portal_pager, CustomerPortal)
from odoo.addons.web.controllers.main import Binary
STATE = ['draft', 'confirmed', 'canceled']
class CustomerPortal(CustomerPortal):
def _prepare_home_portal_values(self, counters):
values = super()._prepare_home_portal_values(counters)
if 'bphtb_count' in counters:
values['bphtb_count'] = request.env['bphtb.sales'].search_count([
('state', 'in', STATE)
]) if request.env['bphtb.sales'].check_access_rights(
'read', raise_exception=False) else 0
return values
def _bphtb_sales_get_page_view_values(self, sales, access_token, **kwargs):
def resize_to_48(b64source):
if not b64source:
b64source = base64.b64encode(Binary.placeholder())
return image_process(b64source, size=(48, 48))
values = {
'sales': sales,
'resize_to_48': resize_to_48,
}
return self._get_page_view_values(sales, access_token, values,
'my_bphtbs_history', False, **kwargs)
@http.route(['/my/bphtb', '/my/bphtb/page/<int:page>'], type='http', auth="user", website=True)
def portal_my_bphtb_saless(self, page=1, date_begin=None, date_end=None, sortby=None, filterby=None, **kw):
values = self._prepare_portal_layout_values()
BphtbSales = request.env['bphtb.sales']
domain = []
if date_begin and date_end:
domain += [('create_date', '>', date_begin), ('create_date', '<=', date_end)]
searchbar_sortings = {
'date': {'label': _('Newest'), 'order': 'create_date desc, id desc'},
'name': {'label': _('Name'), 'order': 'name asc, id asc'},
'owed': {'label': _('Total'), 'order': 'owed desc, id desc'},
}
# default sort by value
if not sortby:
sortby = 'date'
order = searchbar_sortings[sortby]['order']
searchbar_filters = {
'all': {'label': _('All'), 'domain': [('state', 'in', STATE)]},
'draft': {'label': _('Draft'), 'domain': [('state', '=', 'draft')]},
'confirmed': {'label': _('Confirmed'), 'domain': [('state', '=', 'confirmed')]},
'canceled': {'label': _('Canceled'), 'domain': [('state', '=', 'canceled')]},
}
# default filter by value
if not filterby:
filterby = 'all'
domain += searchbar_filters[filterby]['domain']
# count for pager
bphtb_count = BphtbSales.search_count(domain)
# make pager
pager = portal_pager(
url="/my/bphtb",
url_args={
'date_begin': date_begin, 'date_end': date_end,
'sortby': sortby, 'filterby': filterby
},
total=bphtb_count,
page=page,
step=self._items_per_page
)
# search the bphtb orders to display, according to the pager data
saless = BphtbSales.search(
domain,
order=order,
limit=self._items_per_page,
offset=pager['offset']
)
request.session['my_bphtbs_history'] = saless.ids[:100]
values.update({
'date': date_begin,
'saless': saless,
'page_name': 'bphtb',
'pager': pager,
'searchbar_sortings': searchbar_sortings,
'sortby': sortby,
'searchbar_filters': OrderedDict(sorted(searchbar_filters.items())),
'filterby': filterby,
'default_url': '/my/bphtb',
})
return request.render("idg_bphtb.portal_my_bphtb_saless", values)
@http.route(['/my/bphtb/<int:sales_id>'], type='http', auth="public", website=True)
def portal_my_bphtb_sales(self, sales_id=None, access_token=None, **kw):
try:
order_sudo = self._document_check_access('bphtb.sales', sales_id,
access_token=access_token)
except (AccessError, MissingError):
return request.redirect('/my')
report_type = kw.get('report_type')
if report_type in ('html', 'pdf', 'text'):
return self._show_report(model=order_sudo, report_type=report_type,
report_ref='idg_bphtb.action_report_bphtb_sspd',
download=kw.get('download'))
confirm_type = kw.get('confirm')
if confirm_type == 'reminder':
order_sudo.confirm_reminder_mail(kw.get('confirmed_date'))
if confirm_type == 'reception':
order_sudo._confirm_reception_mail()
values = self._bphtb_sales_get_page_view_values(order_sudo, access_token, **kw)
update_date = kw.get('update')
if order_sudo.company_id:
values['res_company'] = order_sudo.company_id
if update_date == 'True':
return request.render("idg_bphtb.portal_my_bphtb_sales_update_date", values)
return request.render("idg_bphtb.portal_my_bphtb_sales", values)
@http.route(['/my/bphtb/<int:sales_id>/update'], type='http',
methods=['POST'], auth="public", website=True)
def portal_my_bphtb_sales_update_dates(self, sales_id=None, access_token=None, **kw):
"""User update scheduled date on bphtb order line.
"""
try:
order_sudo = self._document_check_access('bphtb.sales', sales_id, access_token=access_token)
except (AccessError, MissingError):
return request.redirect('/my')
updated_dates = []
for id_str, date_str in kw.items():
try:
line_id = int(id_str)
except ValueError:
return request.redirect(order_sudo.get_portal_url())
order_sudo.write({
"date": datetime.strptime(date_str, '%Y-%m-%d'),
"state": "confirmed"
})
# line = order_sudo.order_line.filtered(lambda l: l.id == line_id)
# if not line:
# return request.redirect(order_sudo.get_portal_url())
# try:
# updated_date = line._convert_to_middle_of_day(
# datetime.strptime(date_str, '%Y-%m-%d'))
# except ValueError:
# continue
#
# updated_dates.append((line, updated_date))
#
# if updated_dates:
# order_sudo._update_date_planned_for_lines(updated_dates)
return Response(status=204)
id,code,name,min_omzet,rate,disc,company_id:id,under_value
bphtb_01,01,Jual Beli,60000000,5,0,base.main_company,False
bphtb_02,02,Tukar Menukar,60000000,5,0,base.main_company,False
bphtb_03,03,Hibah,60000000,5,0,base.main_company,False
bphtb_04,04,Hibah Wasiat,300000000,5,50,base.main_company,False
bphtb_05,05,Waris,300000000,5,50,base.main_company,False
bphtb_06,06,Pemasukan dalam Perseroan atau Badan Hukum Lainnya,60000000,5,0,base.main_company,False
bphtb_07,07,Pemisahan Hak yang mengakibatkan Peralihan,60000000,5,0,base.main_company,False
bphtb_08,08,Penunjukan Pembelli dalam Lelang,60000000,5,0,base.main_company,True
bphtb_09,09,Pelaksanaan Putusan Hakim yang mempunyai kekuatan hukum tetap,60000000,5,0,base.main_company,True
bphtb_10,10,Penggabungan Usaha,60000000,5,0,base.main_company,False
bphtb_11,11,Peleburan Usaha,60000000,5,0,base.main_company,False
bphtb_12,12,Pemekaran Usaha,60000000,5,0,base.main_company,False
bphtb_13,13,Hadiah,60000000,5,0,base.main_company,False
bphtb_14,14,Perolehan hak Rumah Sederhana Sehat dan RSS melalui KPR bersubsidi,60000000,5,0,base.main_company,False
bphtb_15,15,Pemberian Hak Baru Kelanjutan Pelepasan Hak,60000000,5,0,base.main_company,False
bphtb_16,16,Pemberian hak baru diluar pelepasan hak,60000000,5,0,base.main_company,False
bphtb_17,17,Tax Amnesti,60000000,5,0,base.main_company,False
bphtb_18,18,Peningkatan Status,0,0,0,base.main_company,False
<?xml version="1.0"?>
<odoo>
<data noupdate="1">
<record id="bphtb_01" model=idg_bphtb/data/bphtb.jenis>
<field name='code'>01</field>
<field name='name'>Jual Beli</field>
<field name='min_omzet'>60000000</field>
<field name='rate'>5</field>
<field name='disc'>0</field>
<field name="company_id" ref="base.main_company"/>
<field name='under_value'>False</field>
</record>
<record id="bphtb_02" model=idg_bphtb/data/bphtb.jenis>
<field name='code'>02</field>
<field name='name'>Tukar Menukar</field>
<field name='min_omzet'>60000000</field>
<field name='rate'>5</field>
<field name='disc'>0</field>
<field name="company_id" ref="base.main_company"/>
<field name='under_value'>False</field>
</record>
<record id="bphtb_03" model=idg_bphtb/data/bphtb.jenis>
<field name='code'>03</field>
<field name='name'>Hibah</field>
<field name='min_omzet'>60000000</field>
<field name='rate'>5</field>
<field name='disc'>0</field>
<field name="company_id" ref="base.main_company"/>
<field name='under_value'>False</field>
</record>
<record id="bphtb_04" model=idg_bphtb/data/bphtb.jenis>
<field name='code'>04</field>
<field name='name'>Hibah Wasiat</field>
<field name='min_omzet'>300000000</field>
<field name='rate'>5</field>
<field name='disc'>50</field>
<field name="company_id" ref="base.main_company"/>
<field name='under_value'>False</field>
</record>
<record id="bphtb_05" model=idg_bphtb/data/bphtb.jenis>
<field name='code'>05</field>
<field name='name'>Waris</field>
<field name='min_omzet'>300000000</field>
<field name='rate'>5</field>
<field name='disc'>50</field>
<field name="company_id" ref="base.main_company"/>
<field name='under_value'>False</field>
</record>
<record id="bphtb_06" model=idg_bphtb/data/bphtb.jenis>
<field name='code'>06</field>
<field name='name'>Pemasukan dalam Perseroan atau Badan Hukum Lainnya</field>
<field name='min_omzet'>60000000</field>
<field name='rate'>5</field>
<field name='disc'>0</field>
<field name="company_id" ref="base.main_company"/>
<field name='under_value'>False</field>
</record>
<record id="bphtb_07" model=idg_bphtb/data/bphtb.jenis>
<field name='code'>07</field>
<field name='name'>Pemisahan Hak yang mengakibatkan Peralihan</field>
<field name='min_omzet'>60000000</field>
<field name='rate'>5</field>
<field name='disc'>0</field>
<field name="company_id" ref="base.main_company"/>
<field name='under_value'>False</field>
</record>
<record id="bphtb_08" model=idg_bphtb/data/bphtb.jenis>
<field name='code'>08</field>
<field name='name'>Penunjukan Pembelli dalam Lelang</field>
<field name='min_omzet'>60000000</field>
<field name='rate'>5</field>
<field name='disc'>0</field>
<field name="company_id" ref="base.main_company"/>
<field name='under_value'>True</field>
</record>
<record id="bphtb_09" model=idg_bphtb/data/bphtb.jenis>
<field name='code'>09</field>
<field name='name'>Pelaksanaan Putusan Hakim yang mempunyai kekuatan hukum tetap</field>
<field name='min_omzet'>60000000</field>
<field name='rate'>5</field>
<field name='disc'>0</field>
<field name="company_id" ref="base.main_company"/>
<field name='under_value'>True</field>
</record>
<record id="bphtb_10" model=idg_bphtb/data/bphtb.jenis>
<field name='code'>10</field>
<field name='name'>Penggabungan Usaha</field>
<field name='min_omzet'>60000000</field>
<field name='rate'>5</field>
<field name='disc'>0</field>
<field name="company_id" ref="base.main_company"/>
<field name='under_value'>False</field>
</record>
<record id="bphtb_11" model=idg_bphtb/data/bphtb.jenis>
<field name='code'>11</field>
<field name='name'>Peleburan Usaha</field>
<field name='min_omzet'>60000000</field>
<field name='rate'>5</field>
<field name='disc'>0</field>
<field name="company_id" ref="base.main_company"/>
<field name='under_value'>False</field>
</record>
<record id="bphtb_12" model=idg_bphtb/data/bphtb.jenis>
<field name='code'>12</field>
<field name='name'>Pemekaran Usaha</field>
<field name='min_omzet'>60000000</field>
<field name='rate'>5</field>
<field name='disc'>0</field>
<field name="company_id" ref="base.main_company"/>
<field name='under_value'>False</field>
</record>
<record id="bphtb_13" model=idg_bphtb/data/bphtb.jenis>
<field name='code'>13</field>
<field name='name'>Hadiah</field>
<field name='min_omzet'>60000000</field>
<field name='rate'>5</field>
<field name='disc'>0</field>
<field name="company_id" ref="base.main_company"/>
<field name='under_value'>False</field>
</record>
<record id="bphtb_14" model=idg_bphtb/data/bphtb.jenis>
<field name='code'>14</field>
<field name='name'>Perolehan hak Rumah Sederhana Sehat dan RSS melalui KPR bersubsidi</field>
<field name='min_omzet'>60000000</field>
<field name='rate'>5</field>
<field name='disc'>0</field>
<field name="company_id" ref="base.main_company"/>
<field name='under_value'>False</field>
</record>
<record id="bphtb_15" model=idg_bphtb/data/bphtb.jenis>
<field name='code'>15</field>
<field name='name'>Pemberian Hak Baru Kelanjutan Pelepasan Hak</field>
<field name='min_omzet'>60000000</field>
<field name='rate'>5</field>
<field name='disc'>0</field>
<field name="company_id" ref="base.main_company"/>
<field name='under_value'>False</field>
</record>
<record id="bphtb_16" model=idg_bphtb/data/bphtb.jenis>
<field name='code'>16</field>
<field name='name'>Pemberian hak baru diluar pelepasan hak</field>
<field name='min_omzet'>60000000</field>
<field name='rate'>5</field>
<field name='disc'>0</field>
<field name="company_id" ref="base.main_company"/>
<field name='under_value'>False</field>
</record>
<record id="bphtb_17" model=idg_bphtb/data/bphtb.jenis>
<field name='code'>17</field>
<field name='name'>Tax Amnesti</field>
<field name='min_omzet'>60000000</field>
<field name='rate'>5</field>
<field name='disc'>0</field>
<field name="company_id" ref="base.main_company"/>
<field name='under_value'>False</field>
</record>
<record id="bphtb_18" model=idg_bphtb/data/bphtb.jenis>
<field name='code'>18</field>
<field name='name'>Peningkatan Status</field>
<field name='min_omzet'>0</field>
<field name='rate'>0</field>
<field name='disc'>0</field>
<field name="company_id" ref="base.main_company"/>
<field name='under_value'>False</field>
</record>
</data>
</odoo>
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data noupdate="1">
<record id="bphtb_partner_admin_kab_id" model="res.partner">
<field name="name">Admin BPHTB Kab/Kota</field>
<field name="street">Jalan-jalan</field>
<field name="country_id" ref="base.id"/>
<field name="state_id" ref="base.state_id_jb"/>
<field name="district_id" ref="id_gov.ct_jb_71"/>
<field name="company_id" ref="base.main_company"/>
<field name="zip">90241</field>
<field name="phone">+62 812-345-678</field>
<field name="email">info@company.idexample.com</field>
<field name="website">www.idexample.com</field>
</record>
<record id="bphtb_user_admin_kab_id" model="res.users">
<field name="login">bphtb_admin</field>
<field name="password">admin</field>
<field name="partner_id" ref="bphtb_partner_admin_kab_id"/>
<field name="company_id" ref="base.main_company"/>
<field name="company_ids" eval="[(4,ref('base.main_company'))]"/>
<field name="groups_id"
eval="[(6,0,[ref('base.group_user'), ref('idg_bphtb.group_bphtb_admin')])]"/>
</record>
<record id="bphtb_partner_ppat_kab_id" model="res.partner">
<field name="name">PPAT Kab/Kota</field>
<field name="street">Jalan-jalan</field>
<field name="country_id" ref="base.id"/>
<field name="state_id" ref="base.state_id_jb"/>
<field name="district_id" ref="id_gov.ct_jb_71"/>
<field name="company_id" ref="base.main_company"/>
<field name="zip">90241</field>
<field name="type">ppat</field>
<field name="phone">+62 812-345-678</field>
<field name="email">info@company.idexample.com</field>
<field name="website">www.idexample.com</field>
</record>
<record id="bphtb_user_ppat_kab_id" model="res.users">
<field name="login">ppat</field>
<field name="password">ppat</field>
<field name="partner_id" ref="bphtb_partner_ppat_kab_id"/>
<field name="company_id" ref="base.main_company"/>
<field name="company_ids" eval="[(4,ref('base.main_company'))]"/>
<field name="groups_id"
eval="[(6,0,[ref('base.group_user'), ref('idg_bphtb.group_bphtb_ppat')])]"/>
</record>
<record id="bphtb_partner_wp_kab_id" model="res.partner">
<field name="name">Wajib Pajak BPHTB</field>
<field name="street">Jalan-jalan</field>
<field name="country_id" ref="base.id"/>
<field name="state_id" ref="base.state_id_jb"/>
<field name="district_id" ref="id_gov.ct_jb_71"/>
<field name="company_id" ref="base.main_company"/>
<field name="zip">90241</field>
<field name="type">wp</field>
<field name="phone">+62 812-345-678</field>
<field name="email">info@company.idexample.com</field>
<field name="website">www.idexample.com</field>
</record>
<record id="bphtb_partner_penjual_kab_id" model="res.partner">
<field name="name">Wajib Pajak Penjual BPHTB</field>
<field name="street">Jalan-jalan</field>
<field name="country_id" ref="base.id"/>
<field name="state_id" ref="base.state_id_jb"/>
<field name="district_id" ref="id_gov.ct_jb_71"/>
<field name="company_id" ref="base.main_company"/>
<field name="zip">90241</field>
<field name="type">wp</field>
<field name="phone">+62 812-345-678</field>
<field name="email">info@company.idexample.com</field>
<field name="website">www.idexample.com</field>
</record>
</data>
</odoo>
\ No newline at end of file
id,ppat_id:id,wp_id:id,seller_id:id,state,nop,tax_year,luas_bumi,luas_bng,njop_bumi,njop_bng,luas_bumi_bersama,luas_bng_bersama,njop_bumi_bersama,njop_bng_bersama,jenis_id:id,rate,min_omzet,disc_sk,npop,basic,fine,amount,disc_amount,owed,typ,company_id:id,certicate_no
sspd_01,bphtb_partner_ppat_kab_id,bphtb_partner_wp_kab_id,bphtb_partner_penjual_kab_id,draft,367601000100100010,2021,100,50,500000000,250000000,0,0,00,0,bphtb_01,5,60000000,,1000000000,0,0,0,0,0,sspd,base.main_company,-
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data noupdate="1">
<record id="pdl_partner_company_id" model="res.partner">
<field name="name">Kabupaten/Kota</field>
<field name="street">Jalan-jalan</field>
<field name="country_id" ref="base.id"/>
<field name="state_id" ref="base.state_id_jb"/>
<field name="district_id" ref="id_gov.ct_jb_71"/>
<field name="zip">90241</field>
<field name="phone">+62 812-345-678</field>
<field name="email">info@company.idexample.com</field>
<field name="website">www.idexample.com</field>
</record>
<record id="pdl_company_id" model="res.company">
<field name="name">Kabupaten/Kota Company</field>
<field name="partner_id" ref="pdl_partner_company_id"/>
</record>
</data>
<data>
<function model="res.users" name="write">
<value eval="[ref('base.user_root'), ref('base.user_admin'), ref('base.user_demo')]"/>
<value eval="{'company_ids': [(4, ref('pdl_kab.pdl_company_id'))]}"/>
</function>
</data>
</odoo>
\ No newline at end of file
from . import idg_letter
from datetime import datetime
from odoo import api, fields, models, _
import logging
_logger = logging.getLogger(__name__)
class IdgLetterCategory(models.Model):
_name = 'idg.letter.category'
_description = 'E-Office Category'
name = fields.Char(index=True, string='Name', size=32)
approver_ids = fields.One2many('idg.letter.category.approver', 'category_id', string='Approves')
class IdgLetterCategoryApprover(models.Model):
_name = 'idg.letter.category.approver'
_description = 'E-Office Category Approver'
category_id = fields.Many2one('idg.letter.category')
user_id = fields.Many2one('res.users')
required = fields.Boolean(default=True)
class IdgLetter(models.Model):
_name = 'idg.letter'
_description = 'E Office Master'
_inherit = ['mail.thread', 'mail.activity.mixin']
def _compute_attached_docs_count(self):
Attachment = self.env['ir.attachment']
for rec in self:
rec.doc_count = Attachment.search_count([
'&',
('res_model', '=', 'idg.letter'), ('res_id', '=', rec.id),
])
def attachment_tree_view(self):
action = self.env['ir.actions.act_window']._for_xml_id('base.action_attachment')
action['domain'] = str([
'&',
('res_model', '=', 'idg.letter'),
('res_id', 'in', self.ids),
])
action['context'] = "{'default_res_model': '%s','default_res_id': %d}" % (self._name, self.id)
return action
code = fields.Char(index=True, string='Code', placeholder="Code")
name = fields.Char(index=True, string='Name', size=255, required=True, placeholder="Subject")
state = fields.Selection([('draft', 'Draft'),
('pending', 'Pending'),
('approved', 'Approved'),
('refused', 'Refused'),
('canceled', 'Canceled'),
],
default='draft',
tracking=True,
)
date = fields.Date(string="Date",
required=True,
index=True,
readonly=True,
# states={'draft': [('readonly', False)]},
copy=False,
default=fields.Date.context_today
)
contact_id = fields.Many2one('res.partner',
tracking=True,
required=True, )
category_id = fields.Many2one('idg.letter.category', required=True)
typ = fields.Selection([('in', 'Surat Masuk'),
('out', 'Surat Keluar'),
], default='in')
description = fields.Char()
need_feedback = fields.Boolean()
deadline = fields.Date(string="Deadline",
copy=False,
)
attachment_ids = fields.One2many('ir.attachment', compute='_compute_attachment_ids', string="Main Attachments",
help="Attachment that don't come from message.")
@api.onchange('need_feedback')
def onchange_need_feedback(self):
for rec in self:
if not rec.need_feedback:
rec.deadline = None
else:
if not rec.deadline:
rec.deadline = datetime.today().strftime('%Y-%m-%d')
current_id = fields.Many2one('res.users', default=lambda self: self.env.user, tracking=True,
required=True, )
approver_ids = fields.One2many('idg.letter.approver', 'letter_id', string='Approver', copy=False)
# comments = fields.One2many('idg.letter.comments', 'letter_id', string='Comments', copy=False)
# docs = fields.One2many('idg.letter.docs', 'idg_letter_id', string='Docs', copy=False)
parent_id = fields.Many2one('idg.letter', string='Parent')
childs = fields.One2many('idg.letter', 'parent_id', string='Letter Lines')
doc_count = fields.Integer(compute='_compute_attached_docs_count', string="Number of documents attached")
def _compute_state(self):
for rec in self:
rec.all_state = rec.state
if not rec.approver_ids:
rec.all_state = rec.state
return
for appr in rec.approver_ids:
if appr.state == 'draft':
rec.all_state = 'draft'
return
for appr in rec.approver_ids:
if appr.required and appr.state == 'canceled':
rec.all_state = 'canceled'
rec.state = 'canceled'
return
for appr in rec.approver_ids:
if appr.required and appr.state == 'refused':
rec.all_state = 'refused'
rec.state = 'refused'
return
for appr in rec.approver_ids:
if appr.user_id == self.env.user.id:
rec.all_state = appr.state
return
all_state = fields.Char(compute='_compute_state')
def _compute_user_state(self):
for rec in self:
rec.user_state = None
if rec.state in ["refused", "canceled"]:
rec.user_state = rec.state
return
for appr in rec.approver_ids:
# Jika ada approval baru yang dibuat oleh user aktif maka wajib di submit
if appr.create_uid.id == self.env.user.id and appr.state == 'draft':
rec.user_state = appr.state
return
for appr in rec.approver_ids:
if appr.user_id.id == self.env.user.id:
rec.user_state = appr.state
user_state = fields.Selection([('draft', 'Draft'),
('pending', 'To Approve'),
('approved', 'Approved'),
('refused', 'Refused'),
('canceled', 'Canceled'), ],
compute='_compute_user_state')
def _get_employee_id(self):
employee_rec = self.env['hr.employee'].search([('user_id', '=', self.env.uid)], limit=1)
return employee_rec.id
employee_id = fields.Many2one('hr.employee', string="Employee", default=_get_employee_id, readonly=True,
required=True)
# by default store = False this means the value of this field
# is always computed.
current_user = fields.Many2one('res.users', compute='_get_current_user')
@api.depends()
def _get_current_user(self):
for rec in self:
rec.current_user = self.env.user
# i think this work too so you don't have to loop
self.update({'current_user': self.env.user.id})
def _set_default_approver(self, result):
approver_lines = []
employee = self.env['hr.employee'].search([('user_id', '=', result.create_uid.id)], limit=1)
while employee and employee.parent_id.id:
if employee.parent_id.id:
employee = employee.parent_id
if employee.user_id.id:
approver_lines.append((0, 0, {
'user_id': employee.user_id.id,
"required": True,
"state": "draft"}))
categories = result.category_id.approver_ids
for cat in categories:
approver_lines.append((0, 0, {
'user_id': cat.user_id.id,
"required": True,
"state": "pending"}))
result.approver_ids = approver_lines
@api.model_create_multi
def create(self, vals):
result = super(IdgLetter, self).create(vals)
if result.typ == 'in':
employee_rec = self.env['hr.employee'].search([('user_id', '=', self.env.uid)], limit=1)
department = employee_rec.department_id
while department:
parent = department.parent_id
if not parent:
result.approver_ids = [(0, 0, {
'user_id': department.manager_id.user_id.id,
"required": True,
"state": "pending"})]
department = parent
else:
self._set_default_approver(result)
return result
def write(self, vals):
result = super(IdgLetter, self).write(vals)
return result
def action_submit(self):
self.ensure_one()
for rec in self:
if rec.typ == 'out' and not rec.approver_ids:
self._set_default_approver(rec)
rec.state = "pending"
for appr in rec.approver_ids:
if appr.state == 'draft':
appr.state = 'pending'
def action_draft(self):
for rec in self:
rec.state = "draft"
for appr in rec.approver_ids:
if appr.state != "approved":
appr.state = "draft"
def action_refuse(self):
for rec in self:
for appr in rec.approver_ids:
if appr.user_id.id == self.env.user.id:
rec.state = appr.state = "refused"
def action_cancel(self):
for rec in self:
rec.state = "canceled"
for appr in rec.approver_ids:
if appr.user_id.id == self.env.user.id or appr.state != "approved":
appr.state = "canceled"
def action_approve(self):
for rec in self:
state = "approved"
for appr in rec.approver_ids:
if appr.user_id.id == self.env.user.id:
appr.state = "approved"
if appr.required and appr.state != "approved":
state = appr.state
if state == "approved":
rec.state = "approved"
def action_recall(self):
for rec in self:
for appr in rec.approver_ids:
if appr.user_id.id == self.env.user.id:
appr.state = "pending"
class IdgLetterApprover(models.Model):
_name = 'idg.letter.approver'
_description = 'E Office Letter Approver'
letter_id = fields.Many2one('idg.letter')
user_id = fields.Many2one('res.users')
required = fields.Boolean(string="Required", default=False)
state = fields.Selection([('draft', 'Draft'),
('pending', 'To Approve'),
('approved', 'Approved'),
('refused', 'Refused'),
('canceled', 'Canceled'),
], default='draft',
tracking=True, )
class IdgLetterDocs(models.Model):
_name = 'idg.letter.docs'
_description = 'E Office Documents'
_inherit = ['format.address.mixin', 'image.mixin']
idg_letter_id = fields.Many2one('idg.letter')
name = fields.Char()
class IdgLetterComments(models.Model):
_name = 'idg.letter.comments'
_description = 'E Office Comments'
_inherit = ['format.address.mixin', 'image.mixin']
idg_letter_id = fields.Many2one('idg.letter')
comment = fields.Text()
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data noupdate="0">
<record model="ir.module.category" id="idg_letter">
<field name="name">E-Office Letter Management</field>
<field name="description">E-Office Letter Management</field>
<field name="sequence">11</field>
</record>
<record id="group_idg_letter_user" model="res.groups">
<field name="name">User</field>
<field name="category_id" ref="idg_letter"/>
</record>
<record id="group_idg_letter_admin" model="res.groups">
<field name="name">Administrator</field>
<field name="category_id" ref="idg_letter"/>
<field name="implied_ids" eval="[(4, ref('group_idg_letter_user'))]"/>
<field name="users" eval="[(4, ref('base.user_root')), (4, ref('base.user_admin'))]"/>
</record>
</data>
</odoo>
"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
"access_idg_letter_category_user","access.idg.letter.category.user","model_idg_letter_category","base.group_user",1,0,0,0
"access_idg_letter_user","access.idg.letter.user","model_idg_letter","base.group_user",1,1,1,1
"access_idg_letter_routes_user","access.idg.letter.routes.user","model_idg_letter_routes","base.group_user",1,0,1,0
"access_idg_letter_comments_user","access.idg.letter.comments.user","model_idg_letter_routes","base.group_user",1,0,1,0
"access_idg_letter_docs_user","access.idg.letter.docs.user","model_idg_letter_comments","base.group_user",1,0,1,0
"access_idg_letter_comments_admin","access.idg.letter.comments.admin","model_idg_letter_comments","group_idg_letter_admin",1,1,1,1
"access_idg_letter_docs_admin","access.idg.letter.docs.admin","model_idg_letter_docs","group_idg_letter_admin",1,1,1,1
"access_idg_letter_category_admin","access.idg.letter.category.admin","model_idg_letter_category","group_idg_letter_admin",1,1,1,1
"access_idg_letter_category_user","access.idg.letter.category.user","model_idg_letter_category","group_idg_letter_user",1,1,1,1
"access_idg_letter_category_base","access.idg.letter.category.base","model_idg_letter_category","base.group_user",1,0,0,0
"access_idg_letter_category_approver_base","access.idg.letter.category.approver.base","model_idg_letter_category_approver","base.group_user",1,0,0,0
"access_idg_letter_category_approver_admin","access.idg.letter.category.approver.admin","model_idg_letter_category_approver","group_idg_letter_admin",1,1,1,1
"access_idg_letter_admin","access.idg.letter.admin","model_idg_letter","group_idg_letter_admin",1,1,1,1
"access_idg_letter_approver_admin","access.idg.letter.approver.admin","model_idg_letter_approver","group_idg_letter_admin",1,1,1,1
\ No newline at end of file
"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
"access_idg_letter_category","access.idg.letter.category","model_idg_letter_category","base.group_user",1,0,0,0
"access_idg_letter_category_approver","access.idg.letter.category.approver","model_idg_letter_category_approver","base.group_user",1,0,0,0
"access_idg_letter","access.idg.letter","model_idg_letter","base.group_user",1,1,1,1
"access_idg_letter.approver","access.idg.letter.approver","model_idg_letter_approver","base.group_user",1,1,1,1
"access_idg_letter_category_user","access.idg.letter.category.user","model_idg_letter_category","group_idg_letter_user",1,1,1,0
"access_idg_letter_category_approver_user","access.idg.letter.category.approver.user","model_idg_letter_category_approver","group_idg_letter_user",1,1,1,0
"access_idg_letter_category_admin","access.idg.letter.category.admin","model_idg_letter_category","group_idg_letter_admin",1,1,1,1
"access_idg_letter_category_approver_admin","access.idg.letter.category.approver.admin","model_idg_letter_category_approver","group_idg_letter_admin",1,1,1,1
<?xml version="1.0"?>
<odoo>
<data noupdate="0">
<record model="ir.rule" id="idg_letter_owner_rule">
<field name="name">IDG Letter Owner Rule</field>
<field name="model_id" ref="model_idg_letter"/>
<field name="groups" eval="[4,ref('base.group_user')]"/>
<field name="domain_force">[('create_uid', '=', user.id)]</field>
<field name="perm_read" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_unlink" eval="False"/>
</record>
<record model="ir.rule" id="idg_letter_owner_delete_rule">
<field name="name">IDG Letter Owner Delete Rule</field>
<field name="model_id" ref="model_idg_letter"/>
<field name="groups" eval="[4,ref('base.group_user')]"/>
<field name="domain_force">[('create_uid', '=', user.id), ('state','=','canceled')]</field>
<field name="perm_read" eval="False"/>
<field name="perm_create" eval="False"/>
<field name="perm_write" eval="False"/>
<field name="perm_unlink" eval="True"/>
</record>
<record model="ir.rule" id="idg_letter_write_rule">
<field name="name">IDG Letter Write Rule</field>
<field name="model_id" ref="model_idg_letter"/>
<field name="groups" eval="[4,ref('base.group_user')]"/>
<!-- <field name="domain_force">[('approvers.create_uid', '=', user.id), ('state','in',['draft','new'])]</field>-->
<field name="perm_read" eval="False"/>
<field name="perm_create" eval="False"/>
<field name="perm_write" eval="True"/>
<field name="perm_unlink" eval="False"/>
</record>
<record model="ir.rule" id="idg_letter_approver_read_rule">
<field name="name">IDG Letter Approver Rule</field>
<field name="model_id" ref="model_idg_letter"/>
<field name="groups" eval="[4,ref('base.group_user')]"/>
<field name="domain_force">[('approver_ids.user_id.id', '=', user.id)]</field>
<field name="perm_read" eval="True"/>
<field name="perm_create" eval="False"/>
<field name="perm_write" eval="False"/>
<field name="perm_unlink" eval="False"/>
</record>
<record model="ir.rule" id="idg_letter_approver_write_rule">
<field name="name">IDG Letter Approver Write Rule</field>
<field name="model_id" ref="model_idg_letter_approver"/>
<field name="groups" eval="[4,ref('base.group_user')]"/>
<field name="domain_force">[('required', '=', True)]</field>
<field name="perm_read" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_unlink" eval="False"/>
</record>
<record model="ir.rule" id="idg_letter_approver_delete_rule">
<field name="name">IDG Letter Approver Delete Rule</field>
<field name="model_id" ref="model_idg_letter_approver"/>
<field name="groups" eval="[4,ref('base.group_user')]"/>
<field name="domain_force">[('required', '=', False)]</field>
<field name="perm_read" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_unlink" eval="True"/>
</record>
<record model="ir.rule" id="idg_letter_admin_rule">
<field name="name">IDG Letter Admin Rule</field>
<field name="model_id" ref="model_idg_letter"/>
<field name="groups" eval="[4,ref('group_idg_letter_admin')]"/>
<field name="perm_read" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_unlink" eval="True"/>
</record>
<record model="ir.rule" id="idg_letter_category_admin_rule">
<field name="name">IDG Letter Category Admin Rule</field>
<field name="model_id" ref="model_idg_letter_category"/>
<field name="groups" eval="[4,ref('group_idg_letter_admin')]"/>
<field name="perm_read" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_unlink" eval="True"/>
</record>
<record model="ir.rule" id="idg_letter_category_user_rule">
<field name="name">IDG Letter Category User Rule</field>
<field name="model_id" ref="model_idg_letter_category"/>
<field name="groups" eval="[4,ref('group_idg_letter_user')]"/>
<field name="perm_read" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_unlink" eval="False"/>
</record>
<record model="ir.rule" id="idg_letter_category_rule">
<field name="name">IDG Letter Category Rule</field>
<field name="model_id" ref="model_idg_letter_category"/>
<field name="groups" eval="[4,ref('base.group_user')]"/>
<field name="perm_read" eval="True"/>
<field name="perm_create" eval="False"/>
<field name="perm_write" eval="False"/>
<field name="perm_unlink" eval="False"/>
</record>
<record model="ir.rule" id="idg_letter_category_approver_admin_rule">
<field name="name">IDG Letter Category Approver Admin Rule</field>
<field name="model_id" ref="model_idg_letter_category_approver"/>
<field name="groups" eval="[4,ref('group_idg_letter_admin')]"/>
<field name="perm_read" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_unlink" eval="True"/>
</record>
<record model="ir.rule" id="idg_letter_category_approver_user_rule">
<field name="name">IDG Letter Category Approver User Rule</field>
<field name="model_id" ref="model_idg_letter_category_approver"/>
<field name="groups" eval="[4,ref('group_idg_letter_user')]"/>
<field name="perm_read" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_unlink" eval="False"/>
</record>
<record model="ir.rule" id="idg_letter_category_approver_rule">
<field name="name">IDG Letter Category Approves Rule</field>
<field name="model_id" ref="model_idg_letter_category_approver"/>
<field name="groups" eval="[4,ref('base.group_user')]"/>
<field name="perm_read" eval="True"/>
<field name="perm_create" eval="False"/>
<field name="perm_write" eval="False"/>
<field name="perm_unlink" eval="False"/>
</record>
</data>
</odoo>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<record id="idg_letter_category_tree" model="ir.ui.view">
<field name="name">idg.letter.category.tree</field>
<field name="model">idg.letter.category</field>
<field name="arch" type="xml">
<tree string="Category" sample="1" create="1" delete="1" multi_edit="0">
<field name="name" string="Nama"/>
</tree>
</field>
</record>
<record id="idg_letter_category_form" model="ir.ui.view">
<field name="name">idg.letter.category.form</field>
<field name="model">idg.letter.category</field>
<field name="arch" type="xml">
<form string="Category" sample="1">
<sheet>
<h1>
<field name="name" string="Name"/>
</h1>
<notebook>
<page string="Default Outgoing Message Approval" id="idg_letter_category_approver_page">
<field name="approver_ids"
mode="tree,kanban">
<tree editable="bottom" string="Outgoing Message">
<control>
<create name="add_line_control" string="Add a line"/>
</control>
<field name="user_id"/>
<field name="required"/>
<!-- <field name="name"/>-->
<!-- <field name="phone"/>-->
<!-- <field name="email"/>-->
</tree>
</field>
</page>
</notebook>
</sheet>
</form>
</field>
</record>
<record id="idg_letter_category_action" model="ir.actions.act_window">
<field name="name">Category</field>
<field name="res_model">idg.letter.category</field>
<field name="view_mode">kanban,tree,form</field>
<field name="view_id" ref="idg_letter_category_tree"/>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
Category
</p>
</field>
</record>
<menuitem id="idg_letter_category_menu"
name="Letter Category"
parent="eoffice_config_menu"
action="idg_letter_category_action"
sequence="4"/>
</data>
</odoo>
\ No newline at end of file
<odoo>
<data>
<record id="letter_incoming_tree" model="ir.ui.view">
<field name="name">idg.letter.incoming.tree</field>
<field name="model">idg.letter</field>
<field name="arch" type="xml">
<tree string="Incoming Letter" sample="1" create="1" delete="1" multi_edit="0">
<field name="date"/>
<field name="contact_id" string="From"/>
<field name="code" string="Code"/>
<field name="name" string="Name"/>
<field name="category_id"/>
<field name="need_feedback"/>
<field name="deadline"/>
<field name="state"/>
<field name="create_uid"/>
</tree>
</field>
</record>
<record id="letter_outgoing_tree" model="ir.ui.view">
<field name="name">idg.letter.outgoing.tree</field>
<field name="model">idg.letter</field>
<field name="arch" type="xml">
<tree string="Incoming Letter" sample="1" create="1" delete="1" multi_edit="0">
<field name="date"/>
<field name="contact_id" string="To"/>
<field name="code" string="Code"/>
<field name="name" string="Name"/>
<field name="category_id"/>
<field name="parent_id"/>
<field name="all_state" string="State"/>
<field name="create_uid"/>
</tree>
</field>
</record>
<record id="letter_incoming_form" model="ir.ui.view">
<field name="name">idg.letter.incoming.form</field>
<field name="model">idg.letter</field>
<field name="arch" type="xml">
<form string="Letter">
<header>
<button class="oe_stat_button" name="attachment_tree_view" type="object" icon="fa-file-text-o">
<field string="Documents" name="doc_count" widget="statinfo"/>
</button>
<button name="action_submit" type="object" string="Submit"
attrs="{'invisible':[('user_state','!=', 'draft')]}"/>
<button name="action_approve" type="object" string="Approve"
attrs="{'invisible':[('user_state','in', [False, 'draft', 'approved','canceled', 'refused'])]}"/>
<button name="action_recall" type="object" string="Recall"
attrs="{'invisible':['|',('user_state','in', [False, 'draft','pending']),('state','in',['canceled','refused','approved'])]}"/>
<button name="action_draft" type="object" string="Draft"
attrs="{'invisible':[('state','!=', 'canceled')]}"/>
<button name="action_refuse" type="object" string="Refuse"
attrs="{'invisible':[('user_state','in', [False,'draft','approved','refused','canceled'])]}"/>
<button name="action_cancel" type="object" string="Cancel"
attrs="{'invisible':[('user_state','in', ['approved','canceled'])]}"/>
<field name="state" widget="statusbar"/>
</header>
<sheet>
<group>
<group>
<field name="all_state" invisible="1"/>
<field name="user_state" invisible="1"/>
<field name="current_user" invisible="1"/>
<field name="typ" invisible="1"/>
<div colspan="12">
<h1>
<field name="name" attrs="{'readonly':[('state','!=','draft')]}"
placeholder="Subject"/>
</h1>
</div>
<div colspan="12">
<h2>
<field name="code"
attrs="{'readonly':['|','&amp;', ('state','!=','draft'), ('typ','=' ,'in'), ('typ','=' ,'out')]}"
placeholder="Code" groups="base.group_user"/>
</h2>
<h3>
<field name="code" placeholder="Set Code"
groups="idg_letter.group_idg_letter_user"
attrs="{'readonly': [('state','!=','approved'), ('typ','=' ,'out')]}"/>
</h3>
</div>
<field name="parent_id" string="Reply To"
attrs="{'readonly':[('state','!=','draft')], 'invisible': [('typ','=','in')]}"/>
<field name="contact_id" string="From"
attrs="{'readonly':[('state','!=','draft')], 'invisible':[('typ','=','out')]}"/>
<field name="contact_id" string="To"
attrs="{'readonly':[('state','!=','draft')], 'invisible':[('typ','=','in')]}"/>
<field name="date" attrs="{'readonly':[('state','!=','draft')]}"/>
<field name="category_id" attrs="{'readonly':[('state','!=','draft')]}" required="1"/>
<field name="description" attrs="{'readonly':[('state','!=','draft')]}"/>
<field name="need_feedback" string="Feedback"
attrs="{'readonly':[('state','!=','draft')], 'invisible': [('typ','=','out')]}"/>
<field name="deadline"
attrs="{'required':[('need_feedback', '!=', False)], 'readonly':[('state','!=','draft')], 'invisible': [('typ','=','out')]}"/>
<field name="create_uid" string="Creator" readonly="1"/>
</group>
<group>
<notebook colspan="12">
<page string="Approver" id="letter_route_page">
<field name="approver_ids"
mode="tree,kanban"
widget="section_and_note_one2many">
<tree editable="bottom" string="Approver">
<control>
<create name="add_line_control" string="Add a line"/>
</control>
<field name="user_id" attrs="{'readonly':[('required','=',True)]}"/>
<field name="state" readonly="True"/>
<field name="required" readonly="True"/>
</tree>
</field>
</page>
</notebook>
</group>
</group>
</sheet>
<div class="oe_chatter">
<field name="message_follower_ids" widget="mail_followers"/>
<field name="activity_ids"/>
<field name="message_ids" widget="mail_thread"/>
</div>
</form>
</field>
</record>
<record id="letter_incoming_action" model="ir.actions.act_window">
<field name="name">Incoming Letter</field>
<field name="res_model">idg.letter</field>
<field name="view_mode">tree,form</field>
<field name="domain">[('typ','=','in')]</field>
<field name="view_id" ref="letter_incoming_tree"/>
<field name="context">{'default_typ': 'in'}</field>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
Incoming Letter
</p>
</field>
</record>
<record id="letter_outgoing_action" model="ir.actions.act_window">
<field name="name">Outgoing Letter</field>
<field name="res_model">idg.letter</field>
<field name="view_mode">tree,form</field>
<field name="domain">[('typ','=','out')]</field>
<field name="view_id" ref="letter_outgoing_tree"/>
<field name="context">{'default_typ': 'out'}</field>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
Outgoing Letter
</p>
</field>
</record>
<record id="letter_todo_tree" model="ir.ui.view">
<field name="name">idg.letter.outgoing.tree</field>
<field name="model">idg.letter</field>
<field name="arch" type="xml">
<tree string="Incoming Letter" sample="1" create="0" delete="0" multi_edit="0">
<field name="typ"/>
<field name="date"/>
<field name="contact_id" string="From/To"/>
<field name="code" string="Code"/>
<field name="name" string="Name"/>
<field name="category_id"/>
<field name="parent_id"/>
<field name="create_uid"/>
<field name="user_state" string="Your State"/>
<field name="state" string="State"/>
</tree>
</field>
</record>
<record id="letter_todo_action" model="ir.actions.act_window">
<field name="name">To Dox</field>
<field name="res_model">idg.letter</field>
<field name="view_mode">tree,form</field>
<field name="domain">[('state','=','pending')]</field>
<field name="view_id" ref="letter_todo_tree"/>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
Todo Letter
</p>
</field>
</record>
<record id="letter_task_action" model="ir.actions.act_window">
<field name="name">All Task</field>
<field name="res_model">idg.letter</field>
<field name="view_mode">tree,form</field>
<!-- <field name="domain">['|',('create_uid','=',uid),('approver_ids.user_id','=',uid)]</field>-->
<field name="view_id" ref="letter_todo_tree"/>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
Task Letter
</p>
</field>
</record>
<menuitem id="letter_todo_menu"
name="To Do"
parent="idg_letter_menu"
action="letter_todo_action"
sequence="1"/>
<menuitem id="letter_task_menu"
name="Task"
parent="idg_letter_menu"
action="letter_task_action"
sequence="2"/>
<menuitem id="letter_incoming_menu"
name="Incoming"
parent="idg_letter_menu"
action="letter_incoming_action"
groups="group_idg_letter_user"
sequence="3"/>
<!--groups="idg_eoffice.group_idg_letter_user"-->
<menuitem id="letter_outgoing_menu"
name="Outgoing"
parent="idg_letter_menu"
action="letter_outgoing_action"
sequence="4"/>
</data>
</odoo>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- Top menu item -->
<menuitem id="eoffice_menu_root"
name="E-Office"
web_icon="idg_eoffice,static/description/icon.png"
active="True"
sequence="2"/>
<!-- Transaksi-->
<menuitem id="idg_letter_menu"
name="Letter"
parent="eoffice_menu_root"
sequence="1"/>
<!-- Konfigurasi-->
<menuitem id="eoffice_config_menu"
name="Configuration"
parent="eoffice_menu_root"
sequence="7"/>
<menuitem id="idg_letter_departemen_menu"
name="Departemen"
parent="eoffice_config_menu"
action="hr.hr_department_tree_action"
sequence="1"/>
<menuitem id="idg_letter_employee_menu"
name="Employee"
parent="eoffice_config_menu"
action="hr.open_view_employee_list_my"
sequence="2"/>
</odoo>
<odoo>
<data>
<record id="partner_form_id_bphtb" model="ir.ui.view">
<field name="name">partner.form.id.bphtb.inherit</field>
<field name="model">res.partner</field>
<field name="inherit_id" ref="id_gov.partner_form_id"/>
<field name="groups_id" eval="[(6, 0, [ref('idg_bphtb.group_bphtb_ppat') ])]"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='type']" position="attributes">
<attribute name="invisible">True</attribute>
</xpath>
<xpath expr="//field[@name='category_id']" position="replace"/>
<xpath expr="//field[@name='function']" position="replace"/>
<xpath expr="//field[@name='title']" position="replace"/>
<xpath expr="//page[@name='sales_purchases']" position="attributes">
<attribute name="invisible">1</attribute>
</xpath>
</field>
</record>
<record id="action_ppat_config_idg_bphtb" model="ir.actions.act_window">
<field name="name">PPAT</field>
<field name="res_model">res.partner</field>
<field name="view_mode">kanban,tree,form</field>
<field name="domain">[('type','=','ppat')]</field>
<field name="context">{
'default_is_company': True,
'default_type': 'ppat'}
</field>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
Partner
</p>
</field>
</record>
<record id="action_wp_config_idg_bphtb" model="ir.actions.act_window">
<field name="name">Wajib Pajak</field>
<field name="res_model">res.partner</field>
<field name="view_mode">kanban,tree,form</field>
<field name="domain">[('type','=','wp')]</field>
<field name="context">{
'default_is_company': True,
'default_type': 'wp',
'show_type': 0}
</field>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
Partner
</p>
</field>
</record>
</data>
</odoo>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<template id="portal_my_home_menu_bphtb" name="Portal layout : bphtb menu entries"
inherit_id="portal.portal_breadcrumbs" priority="25">
<xpath expr="//ol[hasclass('o_portal_submenu')]" position="inside">
<li t-if="page_name == 'bphtb' or bphtb_sales"
t-attf-class="breadcrumb-item #{'active ' if not bphtb_sales else ''}">
<a t-if="bphtb_sales" t-attf-href="/my/bphtb?{{ keep_query() }}">Bphtb Transaction</a>
<t t-else="">Bphtb Transaction</t>
</li>
<li t-if="bphtb_sales" class="breadcrumb-item active">
<t t-esc="bphtb_sales.name"/>
</li>
</xpath>
</template>
<template id="portal_my_home_bphtb" name="Show Bphtb Transaction"
customize_show="True"
inherit_id="portal.portal_my_home" priority="25">
<xpath expr="//div[hasclass('o_portal_docs')]" position="inside">
<t t-call="portal.portal_docs_entry">
<t t-set="title">Bphtb Transaction</t>
<t t-set="url" t-value="'/my/bphtb'"/>
<t t-set="placeholder_count" t-value="'bphtb_count'"/>
</t>
</xpath>
</template>
<template id="portal_my_bphtb_saless" name="Portal: My Bphtb Transaction">
<t t-call="portal.portal_layout">
<t t-set="breadcrumbs_searchbar" t-value="True"/>
<t t-call="portal.portal_searchbar"/>
<t t-if="saless" t-call="portal.portal_table">
<thead>
<tr class="active">
<th>Bphtb Transaction #</th>
<th>NOP</th>
<th>Buyer</th>
<th>Seller</th>
<th class="text-right">Date</th>
<th></th>
<th class="text-right">Total</th>
</tr>
</thead>
<tbody>
<t t-foreach="saless" t-as="sales">
<tr>
<td>
<a t-att-href="sales.get_portal_url()">
<t t-esc="sales.name"/>
</a>
</td>
<td>
<span t-field="sales.nop"/>
</td>
<td>
<span t-field="sales.wp_id"/>
</td>
<td>
<span t-field="sales.seller_id"/>
</td>
<td class="text-right">
<span t-field="sales.date"/>
</td>
<td>
<!-- <t t-if="sales.invoice_status == 'to invoice'">-->
<!-- <span class="badge badge-info"><i class="fa fa-fw fa-file-text"/> Waiting for Bill</span>-->
<!-- </t>-->
<t t-if="sales.state == 'draft'">
<span class="badge badge-secondary">
<i class="fa fa-fw fa-firstdraft"/>
Draft
</span>
</t>
<t t-if="sales.state == 'confirmed'">
<span class="badge badge-primary">
<i class="fa fa-fw fa-check-circle"/>
Draft
</span>
</t>
<t t-if="sales.state == 'cancel'">
<span class="badge badge-secondary">
<i class="fa fa-fw fa-remove"/>
Cancelled
</span>
</t>
</td>
<td class="text-right">
<span t-field="sales.owed"/>
</td>
</tr>
</t>
</tbody>
</t>
</t>
</template>
<template id="portal_my_bphtb_sales" name="Portal: My Purchase Order">
<t t-call="portal.portal_layout">
<t t-set="bphtb_sales" t-value="sales"/>
<t t-set="o_portal_fullwidth_alert" groups="idg_bphtb.group_bphtb_admin">
<t t-call="portal.portal_back_in_edit_mode">
<t t-set="backend_url"
t-value="'/web#return_label=Website&amp;model=%s&amp;id=%s&amp;action=%s&amp;view_type=form' % (bphtb_sales._name, bphtb_sales.id, bphtb_sales.id)"/>
</t>
</t>
<div id="optional_placeholder"></div>
<div class="container">
<div class="row mt16 o_portal_bphtb_sidebar">
<!-- Sidebar -->
<t t-call="portal.portal_record_sidebar">
<t t-set="classes" t-value="'col-lg-auto d-print-none'"/>
<t t-set="title">
<h2 class="mb-0">
<b t-field="sales.owed" data-id="owed"/>
</h2>
</t>
<t t-set="entries">
<ul class="list-group list-group-flush flex-wrap flex-row flex-lg-column">
<li class="list-group-item flex-grow-1">
<div class="o_download_pdf btn-toolbar flex-sm-nowrap">
<div class="btn-group flex-grow-1 mr-1 mb-1">
<a class="btn btn-secondary btn-block o_download_btn"
t-att-href="bphtb_sales.get_portal_url(report_type='pdf', download=True)"
title="Download">
<i class="fa fa-download"/>
Download
</a>
</div>
<div class="btn-group flex-grow-1 mb-1">
<a class="btn btn-secondary btn-block o_print_btn o_portal_invoice_print"
t-att-href="bphtb_sales.get_portal_url(report_type='pdf')"
id="print_invoice_report" title="Print" target="_blank">
<i class="fa fa-print"/>
Print
</a>
</div>
</div>
</li>
<li t-if="bphtb_sales.wp_id" class="list-group-item flex-grow-1">
<div class="small mb-1">
<strong class="text-muted">Buyer</strong>
</div>
<div class="row flex-nowrap">
<div class="col flex-grow-0 pr-2">
<img class="rounded-circle mr4 float-left o_portal_contact_img"
t-if="bphtb_sales.wp_id.image_1024"
t-att-src="image_data_uri(bphtb_sales.wp_id.image_1024)"
alt="Buyer"/>
<img class="rounded-circle mr4 float-left o_portal_contact_img"
t-if="not bphtb_sales.wp_id.image_1024"
src="/web/static/src/img/placeholder.png" alt="Buyer"/>
</div>
<div class="col pl-0" style="min-width: 150px">
<span t-field="bphtb_sales.wp_id"
t-options='{"widget": "contact", "fields": ["name", "phone"], "no_marker": True}'/>
<a href="#discussion" class="small">
<i class="fa fa-comment"></i>
Send message
</a>
</div>
</div>
</li>
<li t-if="bphtb_sales.seller_id" class="list-group-item flex-grow-1">
<div class="small mb-1">
<strong class="text-muted">Seller</strong>
</div>
<div class="row flex-nowrap">
<div class="col flex-grow-0 pr-2">
<img class="rounded-circle mr4 float-left o_portal_contact_img"
t-if="bphtb_sales.seller_id.image_1024"
t-att-src="image_data_uri(bphtb_sales.seller_id.image_1024)"
alt="Seller"/>
<img class="rounded-circle mr4 float-left o_portal_contact_img"
t-if="not bphtb_sales.seller_id.image_1024"
src="/web/static/src/img/placeholder.png" alt="Seller"/>
</div>
<div class="col pl-0" style="min-width: 150px">
<span t-field="bphtb_sales.seller_id"
t-options='{"widget": "contact", "fields": ["name", "phone"], "no_marker": True}'/>
<a href="#discussion" class="small">
<i class="fa fa-comment"></i>
Send message
</a>
</div>
</div>
</li>
</ul>
</t>
</t>
<div class=" col-lg col-12 justify-content-end w-100">
<div class="card pb-5">
<div class="card-header bg-white pb-1">
<div class="row">
<div class="col-lg-12">
<h2 class="font-weight-normal">
<t t-if="sales.state in ['draft', 'sent']">Draft</t>
<t t-if="sales.state in ['confirmed']">Confirmed</t>
<t t-if="sales.state in ['canceled']">Canceled</t>
<span class="font-italic" t-esc="sales.name"/>
</h2>
</div>
</div>
</div>
<div class="card-body">
<div class="mb-4">
<strong class="d-block mb-1">From:</strong>
<address t-field="sales.company_id.partner_id"
t-options='{"widget": "contact", "fields": ["address", "name"], "no_marker": True}'/>
<strong>Create Date:</strong>
<span t-field="sales.create_date" t-options='{"widget": "date"}'/>
<br/>
<div t-att-class="'d-inline'">
<strong>Confirmation Date:</strong>
<span t-if="sales.state!='draft'" class="ml-1" t-field="sales.date"
t-options='{"widget": "date"}'/>
<div t-att-class="'d-inline'" t-if="sales.state=='draft'">
<form t-attf-action="/my/bphtb/#{sales.id}/update?access_token=#{sales.access_token}"
method="post">
<input type="hidden" name="csrf_token"
t-att-value="request.csrf_token()"/>
<div class="input-group date col-sm-3">
<input type="text"
class="form-control datetimepicker-input o-bphtb-datetimepicker"
t-attf-id="datetimepicker_#{sales.id}"
t-att-name="sales.id"
data-toggle="datetimepicker"
data-date-format="YYYY-MM-DD"
t-attf-data-target="#datetimepicker_#{sales.id}"/>
<button>Confirm</button>
</div>
</form>
</div>
</div>
</div>
<h3 class="font-weight-normal">Objek Pajak</h3>
<table class="table table-sm">
<tbody>
<tr>
<td>NOP</td>
<td>
<span t-field="sales.nop"/>
<span t-field="sales.tax_year"/>
</td>
<td></td>
</tr>
<tr>
<td>
<strong>Objek</strong>
</td>
<td class="text-right">
<strong>Luas</strong>
</td>
<td class="text-right">
<strong>NJOP</strong>
</td>
</tr>
<tr>
<td>Bumi</td>
<td class="text-right">
<span t-field="sales.luas_bumi"/>
</td>
<td class="text-right">
<span t-field="sales.njop_bumi"/>
</td>
</tr>
<tr>
<td>Bangunan</td>
<td class="text-right">
<span t-field="sales.luas_bng"/>
</td>
<td class="text-right">
<span t-field="sales.njop_bng"/>
</td>
</tr>
<tr>
<td>Bumi Bersama</td>
<td class="text-right">
<span t-field="sales.luas_bumi_bersama"/>
</td>
<td class="text-right">
<span t-field="sales.njop_bumi_bersama"/>
</td>
</tr>
<tr>
<td>Bangunan Bersama</td>
<td class="text-right">
<span t-field="sales.luas_bng_bersama"/>
</td>
<td class="text-right">
<span t-field="sales.njop_bng_bersama"/>
</td>
</tr>
<tr>
<td colspan="2" class="text-right">
<strong>NJOP</strong>
</td>
<td class="text-right">
<strong>
<span t-field="sales.njop"/>
</strong>
</td>
</tr>
</tbody>
</table>
<h3 class="font-weight-normal">Perhitungan</h3>
<table class="table table-sm">
<tr>
<td>Jenis Perolehan</td>
<td>
<span t-field="sales.jenis_id"/>
</td>
</tr>
<tr>
<td>NPOP</td>
<td class="text-right">
<span t-field="sales.npop"/>
</td>
</tr>
<tr>
<td>Dasar Perhitungan</td>
<td class="text-right">
<span t-field="sales.basic_calc"/>
</td>
</tr>
<tr>
<td>NJOPTKP</td>
<td class="text-right">
<span t-field="sales.min_omzet"/>
</td>
</tr>
<tr>
<td>NJKP</td>
<td class="text-right">
<span t-field="sales.npopkp"/>
</td>
</tr>
<tr>
<td>Tarif (%)</td>
<td class="text-right">
<span t-field="sales.rate"/>
</td>
</tr>
<tr>
<td>Pokok</td>
<td class="text-right">
<span t-field="sales.basic"/>
</td>
</tr>
<tr>
<td>Denda</td>
<td class="text-right">
<span t-field="sales.fine"/>
</td>
</tr>
<tr>
<td>Discount (%)</td>
<td class="text-right">
<span t-field="sales.disc"/>
</td>
</tr>
<tr>
<td>Pembayaran</td>
<td class="text-right">
<span t-field="sales.payment"/>
</td>
</tr>
<tr>
<td>
<strong>Terhutang</strong>
</td>
<td class="text-right">
<strong>
<span t-field="sales.owed"/>
</strong>
</td>
</tr>
</table>
</div>
</div>
<div id="bphtb_sales_communication" class="mt-4">
<h2>History</h2>
<t t-call="portal.message_thread">
<t t-set="object" t-value="bphtb_sales"/>
</t>
</div>
</div>
</div>
</div>
<div class="oe_structure mb32"/>
</t>
</template>
<template id="portal_my_bphtb_sales_update_date" name="Portal: My Purchase Order Update Dates"
inherit_id="idg_bphtb.portal_my_bphtb_sales" primary="True">
<xpath expr="//div[hasclass('card-body')]" position="replace">
<div class="card-body">
<div class="mb-4">
<!-- <strong>Confirmation Date:</strong> <span t-field="sales.date_approve" t-options='{"widget": "date"}'/><br/>-->
<!-- <div t-att-class="'d-inline' if sales.date_planned else 'd-none'">-->
<!-- <strong>Receipt Date:</strong><span class="ml-1" t-field="sales.date_planned" t-options='{"widget": "date"}'/>-->
<!-- </div>-->
</div>
<h3 class="font-weight-normal">Pricing</h3>
<table class="table table-sm">
<thead class="bg-100">
<tr>
<th>Products</th>
<th class="text-right d-none d-sm-table-cell">Unit Price</th>
<th class="text-right">Quantity</th>
<th class="text-right">Scheduled Date</th>
<th class="text-right" style="color:#3aadaa">
<strong>Update Dates Here</strong>
</th>
<th class="text-right">Subtotal</th>
</tr>
</thead>
<tbody>
<t t-foreach="sales.sales_line" t-as="ol">
<tr>
<td>
<img t-att-src="image_data_uri(resize_to_48(ol.product_id.image_1024))"
alt="Product" class="d-none d-lg-inline"/>
<span t-esc="ol.name"/>
</td>
<td class="text-right d-none d-sm-table-cell">
<span t-field="ol.price_unit"
t-options='{"widget": "monetary", "display_currency": sales.currency_id}'/>
</td>
<td class="text-right">
<span t-esc="ol.product_qty"/>
</td>
<td class="text-right">
<span t-esc="ol.date_planned.date()"/>
</td>
<td class="text-right">
<form t-attf-action="/my/bphtb/#{sales.id}/update?access_token=#{sales.access_token}"
method="post">
<input type="hidden" name="csrf_token" t-att-value="request.csrf_token()"/>
<div class="container">
<div class="form-group">
<div class="input-group date">
<input type="text"
class="form-control datetimepicker-input o-bphtb-datetimepicker"
t-attf-id="datetimepicker_#{ol.id}" t-att-name="ol.id"
data-toggle="datetimepicker" data-date-format="YYYY-MM-DD"
t-attf-data-target="#datetimepicker_#{ol.id}"/>
</div>
</div>
</div>
</form>
</td>
<td class="text-right">
<span t-field="ol.price_subtotal"
t-options='{"widget": "monetary", "display_currency": sales.currency_id}'/>
</td>
</tr>
</t>
</tbody>
</table>
<div class="row">
<div class="col-sm-7 col-md-5 ml-auto">
<table class="table table-sm">
<tbody>
<tr>
<td>
<strong>Untaxed Amount:</strong>
</td>
<td class="text-right">
<span t-field="sales.amount_untaxed"
t-options='{"widget": "monetary", "display_currency": sales.currency_id}'/>
</td>
</tr>
<tr>
<td>
<strong>Taxes:</strong>
</td>
<td class="text-right">
<span t-field="sales.amount_tax"
t-options='{"widget": "monetary", "display_currency": sales.currency_id}'/>
</td>
</tr>
<tr>
<td>
<strong>Total:</strong>
</td>
<td class="text-right">
<span t-field="sales.owed"
t-options='{"widget": "monetary", "display_currency": sales.currency_id}'/>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</xpath>
</template>
</odoo>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<data>
<menuitem id="base.menu_administration" name="Settings"
web_icon="idg_theme,static/src/img/icons/settinga.png"/>
<menuitem id="base.menu_management" name="Apps" web_icon="idg_theme,static/src/img/icons/apps.png"/>
<menuitem id="mail.menu_root_discuss" name="Discuss"
web_icon="idg_theme,static/src/img/icons/discuss.png"/>
</data>
</odoo>
# -*- coding: utf-8 -*-
from .hooks import test_pre_init_hook, test_post_init_hook
# from . import wizard
# -*- coding: utf-8 -*-
{
"name": "IDG Backend Theme V14",
"description": """Odoo V14 backend theme for Indonesia Government""",
"summary": "Odoo V14 backend theme for Indonesia Government",
"category": "Themes/Backend",
"version": "1.0",
'author': 'bregananta',
'company': 'bregananta',
'maintainer': 'bregananta',
'website': "https://www.bregananta.id",
"depends": ['base', 'web', 'mail', 'web_responsive'],
'images': [],
"data": [
# 'security/ir.model.access.csv',
'views/assets.xml',
'views/icons.xml',
'views/layout.xml',
# 'views/theme.xml',
# 'data/theme_data.xml',
],
"qweb": [
'static/src/xml/sidebar.xml',
'static/src/xml/styles.xml',
'static/src/xml/top_bar.xml',
# 'static/src/xml/systray.xml',
],
'installable': True,
'application': False,
'auto_install': False,
}
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data noupdate="1">
<record id="theme_data_stored" model="theme.data.stored">
<field name="name">default</field>
</record>
</data>
</odoo>
# -*- coding: utf-8 -*-
import base64
from odoo import api, SUPERUSER_ID
from odoo.modules import get_module_resource
def test_pre_init_hook(cr):
"""pre init hook"""
env = api.Environment(cr, SUPERUSER_ID, {})
menu_item = env['ir.ui.menu'].search([('parent_id', '=', False)])
for menu in menu_item:
if menu.name == 'PDL Kab/Kota':
img_path = get_module_resource(
'idg_theme', 'static', 'src', 'img', 'icons', 'idg_pdl.png')
menu.write({'web_icon_data': base64.b64encode(open(img_path, "rb").read())})
if menu.name == 'BPHTB':
img_path = get_module_resource(
'idg_theme', 'static', 'src', 'img', 'icons', 'idg_bphtb.png')
menu.write({'web_icon_data': base64.b64encode(open(img_path, "rb").read())})
def test_post_init_hook(cr, registry):
"""post init hook"""
env = api.Environment(cr, SUPERUSER_ID, {})
menu_item = env['ir.ui.menu'].search([('parent_id', '=', False)])
for menu in menu_item:
if menu.name == 'PDL Kab/Kota':
img_path = get_module_resource(
'idg_theme', 'static', 'src', 'img', 'icons',
'idg_pdl.png')
menu.write({'web_icon_data': base64.b64encode(
open(img_path, "rb").read())})
if menu.name == 'BPHTB':
img_path = get_module_resource(
'idg_theme', 'static', 'src', 'img', 'icons',
'idg_bphtb.png')
menu.write({'web_icon_data': base64.b64encode(
open(img_path, "rb").read())})
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_theme_data,access.theme.data,model_theme_data,,1,1,1,1
<!-- HERO SECTION -->
<div class="contianer">
<div class="row position-relative"
style="background-color: #2f3542 !important; height: 400px; margin-bottom: 6rem; border-radius: 1rem !important;">
<div class="col-lg-12 d-flex flex-column justify-content-start align-items-center">
<h1 class="display-1 text-white" style="padding-top: 5rem;">SDN Theme</h1>
<p class="text-light small font-weight-bold" style="letter-spacing: 2px; text-transform: uppercase;">Backend Theme for
Odoo 14</p>
</div>
</div>
</div>
<!-- END OF HERO SECTION -->
\ No newline at end of file
odoo.define('idg_theme.SideBar', function (require) {
"use strict";
var Widget = require('web.Widget');
var SideBar = Widget.extend({
events: _.extend({}, Widget.prototype.events, {
'click .nav-link': '_onAppsMenuItemClicked',
}),
template: "idg_theme.Sidebar",
init: function (parent, menuData) {
this._super.apply(this, arguments);
this._apps = _.map(menuData.children, function (appMenuData) {
return {
actionID: parseInt(appMenuData.action.split(',')[1]),
menuID: appMenuData.id,
name: appMenuData.name,
xmlID: appMenuData.xmlid,
web_icon_data: appMenuData.web_icon_data,
};
});
},
getApps: function () {
return this._apps;
},
_openApp: function (app) {
this.trigger_up('app_clicked', {
action_id: app.actionID,
menu_id: app.menuID,
});
},
_onAppsMenuItemClicked: function (ev) {
var $target = $(ev.currentTarget);
var actionID = $target.data('action-id');
var menuID = $target.data('menu-id');
var app = _.findWhere(this._apps, { actionID: actionID, menuID: menuID });
this._openApp(app);
},
});
return SideBar;
});
\ No newline at end of file
odoo.define('idg_theme.SidebarMenu', function (require) {
"use strict";
const config = require("web.config");
const Menu = require("web.Menu");
const SideBar = require("idg_theme.SideBar");
Menu.include({
start() {
var res = this._super.apply(this, arguments);
this.sidebar_apps = this.$('.sidebar_panel');
this._sideBar = new SideBar(this, this.menu_data);
var sideBar = this._sideBar.appendTo(this.sidebar_apps);
return res, sideBar
},
});
function showSidebar(){
$("#sidebar_panel").css({'display':'block'});
$(".o_action_manager").css({'margin-left': '90px','transition':'all .1s linear'});
$(".top_heading").css({'margin-left': '78px','transition':'all .1s linear'});
$("#dotsWhite").toggleClass("d-block d-none");
$("#dotsPrimary").toggleClass("d-block d-none");
//add class in navbar
var navbar = $(".o_main_navbar");
var navbar_id = navbar.data("id");
$("nav").addClass(navbar_id);
navbar.addClass("small_nav");
//add class in action-manager
var action_manager = $(".o_action_manager");
var action_manager_id = action_manager.data("id");
$("div").addClass(action_manager_id);
action_manager.addClass("sidebar_margin");
//add class in top_heading
var top_head = $(".top_heading");
var top_head_id = top_head.data("id");
$("div").addClass(top_head_id);
top_head.addClass("sidebar_margin");
}
function hideSidebar(){
$("#sidebar_panel").css({'display':'none'});
$(".o_action_manager").css({'margin-left': '0px'});
$(".top_heading").css({'margin-left': '0px'});
$("#dotsWhite").toggleClass("d-block d-none");
$("#dotsPrimary").toggleClass("d-block d-none");
//remove class in navbar
var navbar = $(".o_main_navbar");
var navbar_id = navbar.data("id");
$("nav").removeClass(navbar_id);
navbar.removeClass("small_nav");
//remove class in action-manager
var action_manager = $(".o_action_manager");
var action_manager_id = action_manager.data("id");
$("div").removeClass(action_manager_id);
action_manager.removeClass("sidebar_margin");
//remove class in top_heading
var top_head = $(".top_heading");
var top_head_id = top_head.data("id");
$("div").removeClass(top_head_id);
top_head.removeClass("sidebar_margin");
}
var showBar = false;
$(document).on("click", "#triggerSidebar", function(event){
if(showBar){
hideSidebar();
}else{
showSidebar();
}
$("#triggerSidebar").toggleClass('c_sidebar_active c_sidebar_passive');
$('#dotsMenuContainer').toggleClass('c_dots_menu c_dots_menu_toggled');
showBar = !showBar;
});
/* $(document).on("click", ".sidebar a", function(event){
var menu = $(".sidebar a");
var $this = $(this);
var id = $this.data("id");
$("header").removeClass().addClass(id);
menu.removeClass("active");
$this.addClass("active");
//sidebar close on menu-item click
$("#sidebar_panel").css({'display':'none'});
$(".o_action_manager").css({'margin-left': '0px'});
$(".top_heading").css({'margin-left': '0px'});
$("#closeSidebar").hide();
$("#openSidebar").show();
//remove class in navbar
var navbar = $(".o_main_navbar");
var navbar_id = navbar.data("id");
$("nav").removeClass(navbar_id);
navbar.removeClass("small_nav");
//remove class in action-manager
var action_manager = $(".o_action_manager");
var action_manager_id = action_manager.data("id");
$("div").removeClass(action_manager_id);
action_manager.removeClass("sidebar_margin");
//remove class in top_heading
var top_head = $(".top_heading");
var top_head_id = top_head.data("id");
$("div").removeClass(top_head_id);
top_head.removeClass("sidebar_margin");
});*/
});
\ No newline at end of file
odoo.define('idg_theme.Load', function (require) {
"use strict";
var rpc = require('web.rpc');
var session = require('web.session');
$(document).ready(function () {
rpc.query({
model: 'theme.data',
method: 'action_apply',
args: [this]
});
});
});
\ No newline at end of file
odoo.define('idg_theme.theme', function (require) {
"use strict";
var SystrayMenu = require('web.SystrayMenu');
var Widget = require('web.Widget');
var Session = require('web.session');
var ThemeWidget = Widget.extend({
template: 'theme_systray',
events: {
'click #theme_sdn': '_onClick',
},
is_admin: false,
willStart: function () {
this.is_admin = Session.is_admin;
return this._super.apply(this, arguments);
},
_onClick: function(){
var menu = $('.o_menu_sections');
this.do_action({
type: 'ir.actions.act_window',
name: 'theme data',
res_model: 'theme.data',
view_mode: 'form',
views: [[false, 'form']],
target: 'new'
});
},
});
SystrayMenu.Items.push(ThemeWidget);
return ThemeWidget;
});
.datepicker{
z-index: 9999 !important;
}
div.dropdown-menu.bootstrap-datetimepicker-widget {
width: 28rem !important;
}
.datepicker .table-sm > thead,
.datepicker > div > table > tbody > tr > td.active{
background-color: $one__primary;
}
.datepicker .table-sm > thead > tr:first-child th:hover {
background-color: $one__primary-dark;
}
.datepicker .table-sm > tbody > tr > td.today::before{
border-bottom-color: $one__primary;
}
.c_login_container{
background: $one__light !important;
width: 100% !important;
.card-body{
background-color: transparent !important;
}
}
.input-group-prepend{
.input-group-text{
border-radius: 0px !important;
border-right: 0px !important;
background: transparent !important;
}
}
.form-control{
border-radius: 0px !important;
border-color: $one__border-light;
background-color: none;
&:focus{
box-shadow: none !important;
}
}
//Buttons
.btn{
border-radius: 0px;
&:hover{
filter: brightness(90%) !important;
box-shadow: none;
transition: $transition-normal;
}
}
.btn-primary{
background-color: $one__primary !important;
border-color: $one__primary !important;
color: $one__light !important;
&:hover{
background-color: $one__primary-dark !important;
}
&:focus{
box-shadow: 0 0 0 0.2rem rgba(235,240,253, 0.8);
}
}
//Links
a, .btn-link {
color: $one__primary;
text-decoration: none;
background-color: transparent;
&:hover{
color: $one__primary-dark;
text-decoration: none !important;
transition: $transition-normal;
}
}
\ No newline at end of file
#sidebar_panel {
height: 100%;
position: fixed;
top: 0px;
background-color: $one__sidebar-color;
border-right: 1px solid $one__sidebar-border;
display: none;
width: 80px;
overflow-y: scroll;
-ms-overflow-style: none; /* Hide scrollbar for IE and Edge */
scrollbar-width: none; /* Hide scrollbar for Firefox */
z-index: 999;
}
#sidebar_panel::-webkit-scrollbar {
display: none; /* Hide scrollbar for Chrome, Safari and Opera */
}
.sidebar_menu{
margin-top: 20px !important;
}
.sidebar_title{
color: $one__sidebar_text;
font-weight: bold;
text-transform: uppercase;
letter-spacing: 2px;
font-size: 0.9rem;
margin-left: auto;
margin-right: auto;
width: 38px;
display: block;
margin-top: 18px !important;
}
.sidebar_panel .sidebar {
padding: 0;
white-space: nowrap;
padding-bottom: 20px;
padding-top: 5px;
}
.sidebar_panel .sidebar_close {
text-align: end;
display: none;
position: sticky;
height: 35px;
padding-top: 5px;
top: 0;
background: #2a3042;
z-index: 1;
}
.sidebar_panel .sidebar_close a#closeSidebar {
font-size: 18px;
margin-right: 10px;
color: #ffffff;
opacity: .3;
}
.sidebar_panel .sidebar_close a#closeSidebar img {
width: 15px;
}
.sidebar_panel .sidebar .sidebar_logo {
padding-top: 20px;
text-align: center;
padding-bottom: 20px;
}
.sidebar_panel .sidebar .sidebar_logo img {
max-width: 150px;
}
.sidebar_panel .sidebar .sidebar_head {
padding-top: 20px;
padding-left: 15px;
color: #6a7187;
font-size: 14px;
}
.sidebar_panel .sidebar .sidebar_menu {
list-style: none;
margin: 0;
padding: 0;
}
.sidebar_panel .sidebar .sidebar_menu li {
margin: 0;
padding: 0;
border: 0px;
display: block;
}
.sidebar_panel .sidebar .sidebar_menu li a {
margin: 0;
border: 0px;
display: block;
cursor: pointer;
overflow: hidden;
padding: 8px 10px 8px 25px;
color: #ffffff;
font-size: 13px;
transition:.3s all;
}
.sidebar_panel .sidebar .sidebar_menu li:hover a {
background: $one__sidebar-color-hover;
color: $one__light;
}
.sidebar_panel .nav-link {
opacity: 1 !important;
transition:.3s all;
}
.sidebar_panel .sidebar a.nav-link.active {
color: $one__light !important;
border-left: 4px solid $one__light;
img{
margin-left: -0.5rem !important;
}
}
.sidebar_panel .sidebar .sidebar_menu li a .sidebar_img {
width: 32px;
height: 32px;
margin: 8px 8px 8px 0;
}
.sidebar_panel .sidebar .sidebar_menu li a {
transition: $transition-fast;
&:hover{
transform: scale(1.1);
transition: $transition-fast;
}
}
\ No newline at end of file
body{
background-color: $one__light !important;
font-family: $one__font;
}
//NAVBAR
.o_main_navbar {
-webkit-box-shadow: 0 0.75rem 1.5rem rgba(18,38,63,.03) !important;
box-shadow: 0 0.75rem 1.5rem rgba(18,38,63,.03) !important;
background-color: $one__light;
border-bottom: none;
-moz-box-shadow: rgba(0, 0, 0, 0.19) 0px 10px 20px, rgba(0, 0, 0, 0.5) 0px 6px 6px;
-webkit-box-shadow: rgba(0, 0, 0, 0.19) 0px 10px 20px, rgba(0, 0, 0, 0.5) 0px 6px 6px;
box-shadow: rgba(0, 0, 0, 0.19) 0px 10px 20px, rgba(0, 0, 0, 0.5) 0px 6px 6px;
color: $one__light-font-primary;
height: 60px !important;
}
// .o-menu-toggle{
// display: none !important;
// }
.c_dots_menu{
background-image: url('/idg_theme/static/src/img/icons/dots-menu.png');
width: 24px;
height: 24px;
background-repeat: no-repeat;
background-size: contain;
}
.c_dots_menu_toggled{
background-image: $dots_menu_toggled;
width: 24px;
height: 24px;
background-repeat: no-repeat;
background-size: contain;
}
li.o_MessagingMenu.o-is-open {
background-color: $one__hover-bkg-light;
border-bottom: none !important;
}
.o_mail_systray_item .o_notification_counter{
background-color: $one__primary !important;
color: $one__light !important;
}
.o_MessagingMenu_counter {
margin-left: -12px !important;
}
.o_MessagingMenu_dropdownMenu.o-mobile,
.o_main_navbar .o_mail_systray_dropdown.show{
top: 60px !important;
max-height: calc(100vh - 60px);
background-color: $one__light !important;
}
.o_notification_counter{
margin-left: -18px !important;
}
.o_NotificationGroup_date{
color: $one__primary !important
}
.o_menu_sections > li > a, .o_main_navbar > li > label{
color: $one__light-font-primary;
font-size: 1.2rem !important;
display: block !important;
height: 60px !important;
line-height: 60px !important;
&:hover{
background-color: $one__hover-bkg-light;
//border-bottom: 1px solid $one__border-light;
}
}
.o_switch_company_menu > a{
color: $one__light-font-primary;
font-size: 1.8rem !important
}
.oe_topbar_name{
color: $one__light-font-primary;
font-size: 1.2rem !important;
}
.o_main_navbar > a:hover, .o_main_navbar > a:focus, .o_main_navbar > button:hover, .o_main_navbar > button:focus {
background-color: $one__hover-bkg-light;
//border-bottom: 1px solid $one__border-light;
}
.o_MessagingMenu, .o_mail_systray_item{
a{
color: $one__light-font-primary;
}
}
.o_MessagingMenu_counter, .o_notification_counter {
background-color: $one__primary;
color: $one__light;
}
.o_main_navbar .show .dropdowdropdown-toggle, .o_main_navbar .show .dropdown-toggle {
background-color: $one__light;
//border-bottom: 1px solid $one__border-light;
}
.o_main_navbar .o_user_menu .oe_topbar_avatar {
height: 32px !important;
width: 32px !important;
}
.oe_topbar_name{
color: $one__light-font-primary !important;
}
.o_dashboards .o_website_dashboard div.o_box h2, .o_dashboards .o_website_dashboard div.o_box h4 {
color: $one__primary !important;
}
.o_control_panel {
padding: 2.5rem 1rem !important;
margin-bottom: 1.5rem !important;
border-bottom: 1px solid $one__border-light;
width: 98%;
margin-left: auto;
margin-right: auto;
}
.o_form_view .oe_button_box .oe_stat_button .o_button_icon {
color: $one__primary;
}
.o_control_panel .breadcrumb > li, .breadcrumb-item > a{
font-size: 2rem !important;
color: $one__light-font-secondary;
}
.breadcrumb-item.active{
$color: $one__light-font-primary;
}
.o_control_panel .breadcrumb-item:nth-last-of-type(2)::before {
color: $one__primary !important;
}
.breadcrumb-item + .breadcrumb-item {
@media (max-width: 767.98px) {
padding: 0.3rem 0.5rem !important;
}
}
.o_form_view .o_form_statusbar > .o_statusbar_status > .o_arrow_button.btn-primary.disabled::after,
.o_form_view .o_form_statusbar > .o_statusbar_status > .o_arrow_button:not(:first-child)::before {
border-left-color: none !important;
}
.o_statusbar_status > .o_arrow_button.btn-secondary{
background-color: $one__light !important;
}
.o_form_view .o_form_statusbar > .o_statusbar_status > .o_arrow_button.disabled {
border-left: none !important;
}
// .o_form_view .o_form_statusbar > .o_statusbar_status > .o_arrow_button:not(:first-child)::before,
// .o_form_view .o_form_statusbar > .o_statusbar_status > .o_arrow_button:not(:first-child)::after {
// background-color: $one__light !important;
// }
.o_content{
width: 98%;
margin-left: auto;
margin-right: auto;
}
.top_heading{
display: flex;
align-items: center;
height: 60px;
ul.o_menu_apps{
list-style: none;
margin: 0 0.8rem 0 0;
padding: 0px;
}
a.o_menu_brand{
color: $one__light-font-primary;
font-size: 1.8rem !important;
}
}
.o_menu_sections, .o_menu_systray{
display: flex;
align-items: center;
list-style: none !important;
height: 60px !important;
li{
margin-right: 1rem;
&:last-child{
margin-right: 0 !important;
}
}
}
.o_menu_systray, .o_menu_sections{
li{
position: relative !important;
a.o_MessagingMenu_toggler, a.dropdown-toggle{
display: flex !important;
align-items: center !important;
height: 60px !important;
padding: 0px 7.5px;
img{
margin-right: 0.8rem;
transform: none !important;
}
}
}
}
.o_main_navbar .dropdown-menu.show {
min-width: auto !important;
}
.o_form_view .o_form_uri > span:first-child {
color: $one__primary;
}
.o_onboarding_container{
margin-top: -1.575rem !important;
}
.o_loading{
background-color: $one__primary !important;
}
.o_menu_systray > li > a > span.fa{
color: $one__light-font-primary;
font-size: 1.9rem !important;
margin: auto 11px !important;
}
@media (max-width: 767.98px) {
.o_menu_systray{
margin: 0 !important;
padding: 0 !important;
li{
margin-right: 0.5rem !important;
}
}
}
//`Custom`
.c_navbar_container{
display: flex;
justify-content: space-between;
width: 100%;
margin-left: auto;
margin-right: auto;
padding: 0 1rem 0 0 !important;
@media (max-width: 991.98px) {
padding: 0 !important;
}
}
.c_sidebar_active{
height: 60px;
width: 70px;
display: flex !important;
justify-content: center;
align-items: center;
background-color: $one__primary;
color: $one__light !important;
margin-right: 1.5rem !important;
clip-path: polygon(0 0, 100% 0%, 86% 100%, 0% 100%);
&:hover{
background-color: $one__primary-dark;
transition: $transition-normal;
}
}
.c_sidebar_passive{
height: 60px;
width: 70px;
display: flex !important;
justify-content: center;
align-items: center;
background-color: $one__light;
color: $one__primary !important;
clip-path: polygon(0 0, 100% 0%, 86% 100%, 0% 100%);
}
//END OF NAVBAR
.dropdown-menu{
border-radius: 10px !important;
a, .dropdown-item{
color: $one__light-font-primary;
&:hover{
color: $one__primary !important;
background-color: $one__primary-light;
transition: $transition-normal;
}
}
}
//Buttons
.btn{
border-radius: $one__border;
padding-left: $one__button-padding !important;
padding-right: $one__button-padding !important;
&:hover{
filter: brightness(90%) !important;
box-shadow: none;
transition: $transition-normal;
}
}
.btn-primary, .o_select_file_button{
background-color: $one__primary !important;
border-color: $one__primary !important;
color: $one__light !important;
&:hover{
background-color: $one__primary-dark !important;
}
&:focus{
box-shadow: 0 0 0 0.2rem rgba(235,240,253, 0.8);
}
}
.btn-secondary{
background-color: $one__hover-bkg-light;
border-color: $one__hover-bkg-light;
color: $one__light-font-primary;
&:focus{
box-shadow: 0 0 0 0.2rem rgba(245,245,245, 1);
}
}
.btn-fill-info, .btn-info {
background-color: $one__info;
border-color: $one__info;
color: $one__light;
}
.btn-group, .o_filter_menu{
button, div.btn-group{
margin-right: 3px;
&:last-child{
margin-right: 0px !important;
}
}
}
.btn-link{
color: $one__primary !important;
&:hover{
background-color: $one__hover-bkg-light !important;
}
}
.o_control_panel .o_cp_bottom_left > .o_cp_action_menus .o_dropdown_toggler_btn {
margin-right: 0px !important;
}
.o_activity_view .o_record_selector, .o_stat_value {
color: $one__primary !important;
}
.o_web_settings_invite{
height: 26px !important;
margin-top: 6px !important;
}
.o_NotificationList{
div:hover {
background-color: $one__primary-light;
}
}
.o_MessagingMenu_tabButton, .o_MessagingMenu_newMessageButton{
color: $one__primary;
opacity: 0.8;
.o-active{
opacity: 1;
font-weight: bold;
}
}
.o_ThreadPreview_date, .o_activity_filter_button, .o_mail_activity_action{
color: $one__primary !important;
&:before{
color: $one__light-font-primary;
}
&:hover{
color: $one__primary-dark !important;
}
}
//Controls
.custom-control.custom-checkbox .custom-control-input:not(:checked):not(:indeterminate) ~ .custom-control-label::before {
background: none;
outline: 1px solid $one__hover-bkg-light;
}
.custom-checkbox .custom-control-label::before {
border-radius: $one__border !important;
}
.custom-control-input:checked ~ .custom-control-label::before {
color: $one__light;
border-color: $one__primary;
background-color: $one__primary;
}
.custom-checkbox .custom-control-input:checked ~ .custom-control-label::after {
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23FFFFFF' d='M6.564.75l-3.59 3.612-1.538-1.55L0 4.26 2.974 7.25 8 2.193z'/%3e%3c/svg%3e");
}
.o_input, .form-control{
border-radius: $one__border !important;
border-color: $one__border-light;
}
.o_required_modifier.o_input, .o_required_modifier .o_input, .o_searchview .o_searchview_autocomplete li.o_selection_focus {
background-color: $one__primary-light !important;
}
.ui-menu-item > a{
background-color: $one__light !important;
color: $one__primary !important;
&:hover, &:active, &:focus, &:focus-within, &:focus-visible, &:visited{
color: $one__primary !important;
background-color: $one__primary-light !important;
}
}
.nav-tabs .nav-link {
border-radius: 0px !important;
border-top: 3px solid transparent !important;
}
.nav-tabs .nav-link.active {
border-top: 3px solid $one__primary !important;
}
.nav-tabs .nav-link:hover{
border-top: 3px solid $one__primary !important;
color: $one__primary-dark;
transition: transition-normal !important;
}
.o_form_view .o_horizontal_separator {
color: $one__primary;
}
.panel-heading.note-toolbar {
background-color: $one__light !important;
}
div.o_boolean_toggle.custom-control.custom-checkbox > input.custom-control-input:checked + label.custom-control-label::before {
background-color: $one__primary !important;
}
//Misc.
.badge-primary{
background-color: $one__primary;
border-radius: $one__border;
padding: 5px;
}
//Links
a {
color: $one__primary;
text-decoration: none;
background-color: transparent;
&:hover{
color: $one__primary-dark;
text-decoration: none;
transition: $transition-normal;
}
}
a.o_menu_brand{
color: $one__light-font-primary;
font-weight: bold;
}
.o_form_uri{
color: $one__primary !important;
}
.o_Message_prettyBody > div > p > a {
background-color: $one__primary !important;
border-radius: $one__border !important;
&:hover{
color: $one__light !important;
}
}
.o_onboarding_step_title > a {
color: $one__light;
}
.oe_kanban_action_a{
color: $one__light-font-primary;
}
.o_kanban_view.o_kanban_grouped .o_kanban_mobile_tabs_container .o_kanban_mobile_tabs .o_kanban_mobile_tab.o_current {
border-bottom: 3px solid $one__primary !important;
}
//Tables
.o_list_view thead {
background-color: $one__hover-bkg-light;
}
.o_list_view .o_list_table thead {
color: $one__light-font-secondary;
border-bottom: 1px solid $one__border-light;
}
.o_list_view .o_list_table thead > tr > th:not(.o_list_record_selector) {
border-left: none;
}
table thead th {
vertical-align: bottom;
border-top: none !important;
border-bottom: none !important;
padding: 1rem !important;
}
table-sm th, .table-sm td {
padding: 1rem !important;
border-top: none !important;
}
tr:nth-child(even){
background-color: $one__hover-bkg-light;
}
.o_list_view .o_list_table tfoot {
background-color: $one__light;
filter: brightness(95.5%) !important;
}
//Search
.o_searchview .o_searchview_facet, .o_setting_search {
background: $one__light;
border-radius: $one__border !important;
border: 1px solid $one__border-light;
color: $one__light-font-secondary;
}
.o_searchview .o_searchview_facet .o_searchview_facet_label {
background-color: $one__light;
}
.o_searchview .o_searchview_input_container .o_searchview_facet .o_searchview_facet_label {
color: $one__light-font-secondary;
margin: 0px -3px 3px 3px;
}
.o_searchview .o_searchview_input_container .o_searchview_facet .o_facet_remove{
bottom: 3px !important;
}
.o_searchview .o_searchview_input_container .o_searchview_facet .o_facet_values {
padding: 2px 18px 0 5px !important;
}
.o_searchview{
padding: 0.5rem !important;
border-radius: $one__border !important;
@media (max-width: 767.98px) {
display: flex;
justify-content: center;
align-items: center;
}
}
.searchInput{
border: none !important;
}
.searchIcon{
margin: 5px 5px 0 0;
}
.o_setting_search {
padding: 5px;
}
//Kanban
.oe_kanban_card{
border-color: $one__border-light;
padding: 1rem !important;
}
//Calendar
@include c_fadeBackgroundOut('fadeCalendarRow', 1, 0.6, 212, 212, 212 );
.o_calendar_sidebar_container .ui-datepicker td.ui-datepicker-current-day.ui-datepicker-today a,
.o_calendar_sidebar_container .ui-datepicker td.ui-datepicker-current-day a,
.o_calendar_view .o_calendar_widget .fc-dayGridMonth-view .fc-content-skeleton .fc-today .fc-day-number
{
color: $one__light !important;
background-color: $one__primary !important;
border-radius: $one__border;
}
.o_calendar_sidebar_container .ui-datepicker td a{
color: $one__light-font-secondary;
}
.o_calendar_sidebar_container .ui-datepicker td.ui-datepicker-today a{
background-color: $one__border-light;
}
.o_calendar_sidebar_container .ui-datepicker .o_selected_range.o_color:not(.ui-datepicker-unselectable) {
animation: fadeCalendarRow 2s forwards;
}
.fc-now-indicator {
border-color: $one__primary !important;
}
.fc-ltr .fc-time-grid .fc-now-indicator-arrow {
left: 0;
border-width: 5px 0 5px 6px;
border-top-color: transparent !important;
border-bottom-color: transparent !important;
}
.o_calendar_view .fc-view .fc-event.o_calendar_color_1.o_cw_custom_highlight {
box-shadow: 0 12px 12px -5px rgba(156, 181, 245, 0.8);
color: $one__primary;
font-weight: bold;
}
.o_calendar_view .fc-view .fc-event.o_calendar_color_1 .fc-bg {
background-color: $one__primary-light;
}
.o_calendar_view .fc-view .fc-event.o_calendar_color_1 {
border-color: $one__primary;
color: #274aa5;
opacity: 0.8;
&:hover{
background: $one__primary-light;
box-shadow: 0 12px 12px -5px rgba(156, 181, 245, 0.8);
}
}
//Dashboard Sidebar
.o_Discuss, .o_setting_container{
width: 98%;
margin-right: auto;
margin-left: auto;
margin-top: -1.5rem !important;
border-top: none;
}
.o_widget_Discuss .o_Discuss_content {
border-top: none !important;
}
.o_DiscussSidebar, .settings_tab{
color: $one__light-font-primary;
background-color: transparent !important;
border-right: 2px solid $one__border-light;
height: 95%;
margin-top: auto;
margin-bottom: auto;
@media (max-width: 767.98px) {
height: auto !important;
}
}
.o_DiscussSidebarItem{
padding: 0.4rem 0 !important;
}
.o_DiscussSidebarItem_activeIndicator.o-item-active{
width: 0;
height: 0;
background: transparent;
margin-top: 0.375rem;
margin-right: 8px !important;
border-top: 5px solid transparent;
border-bottom: 5px solid transparent;
border-left: 5px solid $one__primary;
}
.o_DiscussSidebarItem:hover{
background-color: transparent !important;
color: $one__primary;
}
.o_DiscussSidebar_separator{
width: 95% !important;
margin-left: auto;
margin-right: auto;
background-color: transparent !important;
}
.o_MessageList{
padding: 10px !important;
}
.o_Message.o-not-discussion{
background-color: $one__hover-bkg-light;
border-color: $one__border-light;
}
.o_setting_container .settings_tab {
.app_name{
color: $one__light-font-primary !important;
}
}
.o_setting_container .settings_tab .tab{
height: 30px !important;
}
.o_setting_container .settings{
padding: 10px !important;
}
.o_setting_container .settings_tab .app_name {
color: $one__light-font-primary;
&:hover{
color :$one__primary !important;
}
}
.o_setting_container .settings_tab .selected{
background: transparent !important;
box-shadow: none !important;
position: relative;
&:before{
content: "";
position: absolute;
width: 0;
height: 0;
top: 24%;
left: 0;
background: transparent;
margin-top: 0.375rem;
border-top: 5px solid transparent;
border-bottom: 5px solid transparent;
border-left: 5px solid $one__primary;
}
.app_name{
color: $one__light-font-primary;
&:hover{
color :$one__primary !important;
}
}
}
.o_base_settings .o_setting_container .settings_tab .tab{
line-height: 32px;
}
.o_search_panel .o_search_panel_category .o_search_panel_section_icon {
color: $one__primary;
}
.o_search_panel .list-group-item header.active {
background-color: $one__primary-light;
color: $one__primary;
}
//Chat
.o_ChatWindowHeader{
background-color: $one__primary !important;
color: $one__light !important;
border-radius: $one__border !important;
}
//Tables
.o_purchase_dashboard .table > thead > tr > td.o_main, .o_purchase_dashboard .table tbody > tr > td.o_main {
background-color: $one__primary !important;
&:hover{
background-color: $one__primary-dark;
}
a{
color: $one__light;
}
}
//Tags
.o_field_widget.o_field_many2manytags .o_tag_color_5,
.o_kanban_view .o_kanban_record .o_field_many2manytags .o_tag.o_tag_color_5 span,
.o_kanban_view .o_kanban_record .o_kanban_tags .o_tag.o_tag_color_5 span {
background-color: $one__primary;
}
.badge-pill{
a{
color: $one__light;
}
}
.oe_kanban_card .o_kanban_tags .o_tag, .o_kanban_view .o_kanban_record .o_field_many2manytags .o_tag, .o_kanban_view .o_kanban_record .o_kanban_tags .o_tag {
background-color: transparent !important;
}
//Responsive Menu
@media (max-width: 767.98px) {
.o-menu-toggle{
border: none !important;
background: transparent !important;
height: 60px !important;
display: flex !important;
justify-content: center !important;
align-items: center !important;
}
.dropdown-toggle{
width: 100% !important;
}
.o_main_navbar .o_menu_sections.show{
background: $one__light !important;
padding: 0px !important;
align-items: flex-start !important;
height: 100vh !important;
top: 60px !important;
margin-top: 20px !important;
li {
height: 40px !important;
font-weight: bolder;
a{
padding-left: 7px !important;
}
}
}
.o_main_navbar .show .dropdown-toggle {
background-color: $one__light !important;
width: 100% !important;
}
.o_main_navbar .o_menu_sections.show > li{
width: 100% !important;
}
.o_main_navbar .o_menu_sections.show .show {
width: 100% !important;
}
.o_main_navbar .o_menu_sections.show .show .dropdown-menu {
width: 100% !important;
border-radius: 0px !important;
border: none !important;
margin-left: 0rem !important;
box-shadow: none !important;
}
.o_mail_systray_dropdown{
margin-top: 20px !important;
}
}
//Override Search Pannel width
.o_search_panel.account_root {
flex: 0 0 150px !important;
padding: 6px;
scrollbar-width: thin;
.o_search_panel_section_header {
display: none;
}
.list-group-item span.o_search_panel_label_title {
display: contents;
}
.o_search_panel_category_value {
header {
margin-left: 0;
padding-left: 0;
}
.o_search_panel_category_value .o_toggle_fold {
width: 0.3rem;
}
}
&::-webkit-scrollbar {
width: 4px;
}
&::-webkit-scrollbar-thumb {
background: lightgray;
}
}
\ No newline at end of file
//Variables
//Fonts
$one__font: "Odoo Unicode Support Noto", "Lucida Grande", Helvetica, Verdana, Arial, sans-serif;
//Colors
$one__light: #FFF !default;
$one__primary: #386aeb !default;
$one__sidebar-color-hover: #274aa5 !important;
$one__sidebar-border: #386aeb !important;
$one__sidebar-color: #386aeb !important;
$one__sidebar_text: #fff !default;
$one__primary-light: #ebf0fd !default;
$one__primary-dark: #274aa5 !important;
$one__light-font-primary: #1f2631 !important;
$one__light-font-secondary: #575757 !important;
$one__hover-bkg-light: #f5f5f5 !important;
$one__border-light: #d4d4d4 !important;
$one__info: #454555 !important;
//Border Style
$one__border: 0px;
$one__button-padding: auto;
//Misc
$transition-normal: all 0.4s linear !default;
$transition-fast: all 0.2s linear !default;
//Paths
$dots_menu_toggled: url('/idg_theme/static/src/img/icons/dots-menu-primary.png');
//Animations
@mixin c_fadeBackgroundOut($name, $s_opacity, $e_opacity, $r, $g, $b){
@keyframes #{$name}{
0%{
background-color: rgba($r, $g, $b, $s_opacity);
}
100%{
background-color: rgba($r, $g, $b, $e_opacity);
}
}
}
\ No newline at end of file
//Variables
//Fonts
$one__font: 'Nunito', Helvetica, Verdana, Arial, sans-serif !important;
//Colors
$one__light: #fff !default;
$one__primary: #1F2631 !default;
$one__sidebar-color: #1F2631 !important;
$one__sidebar-color-hover: #1c222c !default;
$one__sidebar-border: #1F2631 !important;
$one__sidebar_text: #fff !default;
$one__primary-light: #e9e9ea !default;
$one__primary-dark: #1c222c !important;
$one__light-font-primary: #030405 !important;
$one__light-font-secondary: #575757 !important;
$one__hover-bkg-light: #f5f5f5 !important;
$one__border-light: #d4d4d4 !important;
$one__info: #454555 !important;
//Border Style
$one__border: 100px;
$one__button-padding: 20px;
//Misc
$transition-normal: all 0.4s linear !default;
$transition-fast: all 0.2s linear !default;
//Paths
$dots_menu_toggled: url('/idg_theme/static/src/img/icons/dots-menu-navy.png');
//Animations
@mixin c_fadeBackgroundOut($name, $s_opacity, $e_opacity, $r, $g, $b){
@keyframes #{$name}{
0%{
background-color: rgba($r, $g, $b, $s_opacity);
}
100%{
background-color: rgba($r, $g, $b, $e_opacity);
}
}
}
//Variables
//Fonts
$one__font: 'Poppins', Helvetica, Verdana, Arial, sans-serif !important;
//Colors
$one__light: #fff !default;
$one__primary: #00A97F !default;
$one__sidebar-color: #fff !important;
$one__sidebar-color-hover: #e6f6f2 !default;
$one__sidebar-border: #E9E9E9 !important;
$one__sidebar_text: #00A97F !default;
$one__primary-light: #e6f6f2 !default;
$one__primary-dark: #009872 !important;
$one__light-font-primary: #575757 !important;
$one__light-font-secondary: #575757 !important;
$one__hover-bkg-light: #f5f5f5 !important;
$one__border-light: #d4d4d4 !important;
$one__info: #454555 !important;
//Border Style
$one__border: 3px;
$one__button-padding: auto;
//Misc
$transition-normal: all 0.4s linear !default;
$transition-fast: all 0.2s linear !default;
//Paths
$dots_menu_toggled: url('/idg_theme/static/src/img/icons/dots-menu-green.png');
//Animations
@mixin c_fadeBackgroundOut($name, $s_opacity, $e_opacity, $r, $g, $b){
@keyframes #{$name}{
0%{
background-color: rgba($r, $g, $b, $s_opacity);
}
100%{
background-color: rgba($r, $g, $b, $e_opacity);
}
}
}
<?xml version="1.0" encoding="UTF-8"?>
<templates id="template" xml:space="preserve">
<t t-extend="Menu">
<t t-jquery=".o_main_navbar" t-operation="after">
<div class="sidebar_panel" id="sidebar_panel"/>
</t>
</t>
<t t-name="idg_theme.Sidebar">
<div class="sidebar">
<div class="sidebar_close">
<a id="closeSidebar" style="cursor: pointer;">
<img src="/idg_theme/static/src/img/icons/close.png"/>
</a>
</div>
<!-- <div class="sidebar_logo">-->
<!-- <img src="/web/binary/company_logo" class="logo_img"/>-->
<!-- </div>-->
<span class="sidebar_title">
Menu
</span>
<ul class="sidebar_menu">
<t t-foreach="widget.getApps()" t-as="app">
<li data-toggle="tooltip" data-placement="right" t-att-title="app.name">
<a role="menuitem" t-attf-href="#menu_id=#{app.menuID}"
class="nav-link" t-att-data-menu-id="app.menuID"
t-att-data-menu-xmlid="app.xmlID"
t-att-data-action-id="app.actionID">
<img class="sidebar_img"
t-attf-src="data:image/svg;base64,#{app.web_icon_data}"/>
</a>
</li>
</t>
</ul>
</div>
</t>
</templates>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<templates id="template" xml:space="preserve">
<!--Align Invite Button in Settings-->
<t t-inherit="base_setup.res_config_invite_users" t-inherit-mode="extension" owl="1">
<xpath expr="//div[hasclass('d-flex')]" position="attributes">
<attribute name="class">d-flex align-items-center</attribute>
</xpath>
</t>
<!--Remove App Icon in Settings-->
<t t-inherit="web.BaseSetting.Tabs" t-inherit-mode="extension" owl="1">
<xpath expr="//div[hasclass('tab')]" position="replace">
<div class="tab" t-attf-data-key="#{tab.key}" role="tab">
<span class="app_name"><t t-esc="tab.string"/></span>
</div>
</xpath>
</t>
<!--Active Color for App Counter-->
<t t-inherit="web.SearchPanel.Category" t-inherit-mode="extension" owl="1">
<xpath expr="//span[hasclass('o_search_panel_counter')]" position="attributes">
<attribute name="class">o_search_panel_counter ml-2 small</attribute>
</xpath>
</t>
</templates>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8" ?>
<templates>
<t t-name="theme_systray">
<li class="new_icon">
<label class="theme_sdn" style="margin-bottom:0px;" title="Change backend theme">
<t t-if="widget.is_admin">
<div class="icon_div sdn_systray_icon" groups="base.group_system">
<div class="toggle-icon"
style="font-size: 1.9rem !important; margin: auto 11px !important;">
<i id='theme_sdn' class="fa fa-paint-brush" role="img" aria-label="Theme"/>
</div>
</div>
</t>
</label>
</li>
</t>
</templates>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<templates id="template" xml:space="preserve">
<t t-inherit="web.Menu" t-inherit-mode="extension" owl="1">
<xpath expr="//nav[hasclass('o_main_navbar')]" position="replace">
<nav class="o_main_navbar">
<div class="c_navbar_container">
<div class="top_heading d-flex align-items-center">
<ul class="o_menu_apps"/>
<a class="o_menu_brand" role="button"/>
<!-- Current App Sections -->
<div class="d-none d-md-block">
<ul class="o_menu_sections mb-0 pl-4" role="menu"/>
</div>
</div>
<div class="d-flex justify-content-between c_responsive_tray">
<ul class="o_menu_systray topbar_icon" role="menu"/>
</div>
</div>
</nav>
</xpath>
</t>
<t t-inherit="web.AppsMenu" t-inherit-mode="extension" owl="1">
<xpath expr="//li[hasclass('dropdown')]" position="replace">
<li class="dropdown">
<a id="triggerSidebar" class="c_sidebar_active" style="display: block; cursor: pointer;">
<!-- <i class="fa fa-th-large fa-lg"/> -->
<div id="dotsMenuContainer" class="c_dots_menu"/>
</a>
</li>
</xpath>
</t>
<t t-inherit="web.UserMenu" t-inherit-mode="extension" owl="1">
<xpath expr="//span[hasclass('oe_topbar_name')]" position="replace">
<div class="oe_topbar_name"/>
</xpath>
</t>
<t t-inherit="mail.MessagingMenu" t-inherit-mode="extension" owl="1">
<xpath expr="//i[hasclass('o_MessagingMenu_icon')]" position="replace">
<img src="/idg_theme/static/src/img/icons/speech-bubble.png" width="22" height="22" aria-label="Messages"/>
</xpath>
</t>
<t t-inherit="mail.systray.ActivityMenu" t-inherit-mode="extension" owl="1">
<xpath expr="//i[hasclass('fa-clock-o')]" position="replace">
<img src="/idg_theme/static/src/img/icons/bell.png" width="22" height="22" aria-label="Activities"/>
</xpath>
</t>
</templates>
\ No newline at end of file
<odoo>
<data>
<template id="idg_theme_assets" name="SDN Theme Assets" inherit_id="web.assets_backend">
<xpath expr=".">
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;600&amp;display=swap" rel="stylesheet"/>
<link href="https://fonts.googleapis.com/css2?family=Nunito:wght@300;400;600&amp;display=swap" rel="stylesheet"/>
<link rel="stylesheet" href="/idg_theme/static/src/scss/theme_accent.scss"/>
<link rel="stylesheet" href="/idg_theme/static/src/scss/datetimepicker.scss"/>
<link rel="stylesheet" href="/idg_theme/static/src/scss/theme.scss"/>
<link rel="stylesheet" href="/idg_theme/static/src/scss/sidebar.scss"/>
<script type="application/javascript" src="/idg_theme/static/src/js/chrome/sidebar.js"/>
<script type="application/javascript" src="/idg_theme/static/src/js/chrome/sidebar_menu.js"/>
<!-- <script type="application/javascript" src="/idg_theme/static/src/js/systray.js"/> -->
<!-- <script type="application/javascript" src="/idg_theme/static/src/js/load.js"/> -->
</xpath>
</template>
<template id="idg_theme_assets_frontend" inherit_id="web.assets_frontend">
<xpath expr="//link[last()]" position="after">
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;600&amp;display=swap" rel="stylesheet"/>
<link href="https://fonts.googleapis.com/css2?family=Nunito:wght@300;400;600&amp;display=swap" rel="stylesheet"/>
<link rel="stylesheet" href="/idg_theme/static/src/scss/theme_accent.scss"/>
<link rel="stylesheet" href="/idg_theme/static/src/scss/login.scss"/>
</xpath>
</template>
</data>
</odoo>
<odoo>
<data>
<template>
<t t-name="DashBoard.action">
<div t-att-data-id="action.attrs.id" class="oe_action">
<h2 t-attf-class="oe_header #{action.attrs.string ? '' : 'oe_header_empty'}">
<span class="oe_header_txt"> <t t-esc="action.attrs.string"/> </span>
<input class = "oe_header_text" type="text"/>
<t t-if="!action.attrs.string">&amp;nbsp;</t>
<span class='oe_icon oe_minimize oe_fold' t-if="!action.attrs.fold"></span>
<span class='oe_icon oe_maximize oe_fold' t-if="action.attrs.fold"></span>
</h2>
<div t-att-class="'oe_content' + (action.attrs.fold ? ' oe_folded' : '')"/>
</div>
</t>
<t t-name="DashBoard.NoContent">
<div class="o_view_nocontent">
<div class="o_nocontent_help">
<p class="o_view_nocontent_neutral_face">
Your personal dashboard is empty
</p><p>
To add your first report into this dashboard, go to any
menu, switch to list or graph view, and click <i>"Add to
Dashboard"</i> in the extended search options.
</p><p>
You can filter and group data before inserting into the
dashboard using the search options.
</p>
</div>
</div>
</t>
</template>
</data>
</odoo>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<template id="code_custom_layout" inherit_id="web.layout"
name="Custom Layout">
<xpath expr="//meta[@content='IE=edge,chrome=1']" position="after">
<meta name="viewport"
content="width=device-width, initial-scale=1, user-scalable=no"/>
</xpath>
</template>
<template id="code_custom_login" inherit_id="web.login"
name="Custom Layout">
<xpath expr="//t[@t-call='web.login_layout']" position="replace">
<t t-call="web.login_layout">
<form class="oe_login_form" role="form"
t-attf-action="/web/login" method="post"
onsubmit="this.action = '/web/login' + location.hash">
<input type="hidden" name="csrf_token"
t-att-value="request.csrf_token()"/>
<div class="form-group field-db"
t-if="databases and len(databases) &gt; 1">
<label for="db" class="col-form-label">Database</label>
<div t-attf-class="input-group {{'input-group-sm' if form_small else ''}}">
<input type="text" name="db"
t-att-value="request.db" id="db"
t-attf-class="form-control #{'form-control-sm' if form_small else ''}"
required="required" readonly="readonly"/>
<span class="input-group-append">
<a role="button" href="/web/database/selector"
class="btn btn-secondary">Select
<i class="fa fa-database" role="img"
aria-label="Database"
title="Database"></i>
</a>
</span>
</div>
</div>
<div class="form-group field-login">
<label class="sr-only" for="login">Email</label>
<div class="input-group">
<div class="input-group-prepend">
<div class="input-group-text">
<i class="fa fa-envelope"></i>
</div>
</div>
<input type="text" placeholder="Email" name="login"
t-att-value="login" id="login"
t-attf-class="form-control border-left-0 #{'form-control-sm' if form_small else ''}"
required="required" autofocus="autofocus"
autocapitalize="off"/>
</div>
</div>
<div class="form-group field-password">
<label for="password" class="sr-only">Password</label>
<div class="input-group">
<div class="input-group-prepend">
<div class="input-group-text">
<i class="fa fa-asterisk"></i>
</div>
</div>
<input type="password" placeholder="Password"
name="password" id="password"
t-attf-class="form-control border-left-0 #{'form-control-sm' if form_small else ''}"
required="required"
autocomplete="current-password"
t-att-autofocus="'autofocus' if login else None"
maxlength="4096"/>
</div>
</div>
<p class="alert alert-danger" t-if="error" role="alert">
<t t-esc="error"/>
</p>
<p class="alert alert-success" t-if="message" role="status">
<t t-esc="message"/>
</p>
<div t-attf-class="clearfix oe_login_buttons text-center mb-1 {{'pt-2' if form_small else 'pt-3'}}">
<button type="submit" class="btn btn-primary btn-block">
Log in
</button>
<t t-if="debug">
<button type="submit" name="redirect"
value="/web/become"
class="btn btn-link btn-sm btn-block">Log in
as superuser
</button>
</t>
<div class="o_login_auth"/>
</div>
<input type="hidden" name="redirect"
t-att-value="redirect"/>
</form>
</t>
</xpath>
</template>
</odoo>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="idg_theme_data" model="ir.ui.view">
<field name="name">them.data.form</field>
<field name="model">theme.data</field>
<field name="arch" type="xml">
<form create="0">
<footer>
<button name="action_apply" id="jsxj" type="object" string="Apply" class="btn btn-primary"/>
</footer>
<sheet>
<group>
<group>
<field name="name"/>
</group>
</group>
</sheet>
</form>
</field>
</record>
</odoo>
\ No newline at end of file
# -*- coding: utf-8 -*-
import base64
from odoo import models, fields, api
from odoo.modules import get_module_resource
class Theme(models.TransientModel):
_name = "theme.data"
def _get_current_theme(self):
return self.env['theme.data.stored'].sudo().search([], limit=1).name
name = fields.Selection([
('default', 'Default'),
('two', 'Green'),
('three', 'Black'),
], 'Theme', required=True, default=_get_current_theme)
@api.onchange('name')
def onchange_name(self):
theme = self.sudo().env.ref('idg_theme.theme_data_stored')
if theme:
theme.name = self.name
else:
theme.create({
'name': self.name
})
def action_apply(self):
name = self.env['theme.data.stored'].sudo().search([], limit=1).name
if name == 'two':
link = '<link rel="stylesheet" href="/idg_theme/static/src/scss/theme_two.scss"/>'
self.icon_change_theme_green()
elif name == 'three':
link = '<link rel="stylesheet" href="/idg_theme/static/src/scss/theme_three.scss"/>'
self.icon_change_theme_default()
else:
link = '<link rel="stylesheet" href="/idg_theme/static/src/scss/theme_accent.scss"/>'
self.icon_change_theme_default()
theme = self.sudo().env.ref('idg_theme.idg_theme_assets')
login = self.sudo().env.ref(
'idg_theme.idg_theme_assets_frontend')
theme.arch_base = '''
<data name="SDN Theme Assets" inherit_id="web.assets_backend">
<xpath expr=".">
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;600&amp;display=swap" rel="stylesheet"/>
<link href="https://fonts.googleapis.com/css2?family=Nunito:wght@300;400;600&amp;display=swap" rel="stylesheet"/>
%s
<link rel="stylesheet" href="/idg_theme/static/src/scss/datetimepicker.scss"/>
<link rel="stylesheet" href="/idg_theme/static/src/scss/theme.scss"/>
<link rel="stylesheet" href="/idg_theme/static/src/scss/sidebar.scss"/>
<script type="application/javascript" src="/idg_theme/static/src/js/chrome/sidebar.js"/>
<script type="application/javascript" src="/idg_theme/static/src/js/chrome/sidebar_menu.js"/>
<script type="application/javascript" src="/idg_theme/static/src/js/systray.js"/>
<script type="application/javascript" src="/idg_theme/static/src/js/load.js"/>
</xpath>
</data>
''' % link
login.arch_base = '''
<data name="idg_theme_assets_frontend" inherit_id="web.assets_backend">
<xpath expr=".">
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;600&amp;display=swap" rel="stylesheet"/>
<link href="https://fonts.googleapis.com/css2?family=Nunito:wght@300;400;600&amp;display=swap" rel="stylesheet"/>
%s
<link rel="stylesheet" href="/idg_theme/static/src/scss/login.scss"/>
</xpath>
</data>
''' % link
return {
'type': 'ir.actions.client',
'tag': 'reload',
}
def icon_change_theme_default(self):
menu_item = self.env['ir.ui.menu'].sudo().search([('parent_id', '=', False)])
for menu in menu_item:
if menu.name == 'PDL Kab/Kota':
img_path = get_module_resource(
'idg_theme', 'static', 'src', 'img', 'icons',
'idg_pdl.png')
menu.write({'web_icon_data': base64.b64encode(
open(img_path, "rb").read())})
if menu.name == 'BPHTB':
img_path = get_module_resource(
'idg_theme', 'static', 'src', 'img', 'icons',
'idg_bphtb.png')
menu.write({'web_icon_data': base64.b64encode(
open(img_path, "rb").read())})
if menu.name == 'IDG Account':
img_path = get_module_resource(
'idg_theme', 'static', 'src', 'img', 'icons',
'idg_account.png')
menu.write({'web_icon_data': base64.b64encode(
open(img_path, "rb").read())})
if menu.name == 'ID Dashboard':
img_path = get_module_resource(
'idg_theme', 'static', 'src', 'img', 'icons',
'idg_board.png')
menu.write({'web_icon_data': base64.b64encode(
open(img_path, "rb").read())})
def icon_change_theme_green(self):
menu_item = self.env['ir.ui.menu'].sudo().search([('parent_id', '=', False)])
for menu in menu_item:
if menu.name == 'PDL Kab/Kota':
img_path = get_module_resource(
'idg_theme', 'static', 'src', 'img',
'icons_light',
'idg_pdl.png')
menu.write({'web_icon_data': base64.b64encode(
open(img_path, "rb").read())})
if menu.name == 'BPHTB':
img_path = get_module_resource(
'idg_theme', 'static', 'src', 'img',
'icons_light',
'idg_bphtb.png')
menu.write({'web_icon_data': base64.b64encode(
open(img_path, "rb").read())})
if menu.name == 'IDG Account':
img_path = get_module_resource(
'idg_theme', 'static', 'src', 'img',
'icons_light',
'idg_account.png')
menu.write({'web_icon_data': base64.b64encode(
open(img_path, "rb").read())})
if menu.name == 'ID Dashboard':
img_path = get_module_resource(
'idg_theme', 'static', 'src', 'img',
'icons_light',
'idg_board.png')
menu.write({'web_icon_data': base64.b64encode(
open(img_path, "rb").read())})
class ThemeStored(models.Model):
_name = "theme.data.stored"
name = fields.Selection([
('default', 'Default'),
('two', 'Green'),
('three', 'Black'),
], 'Theme', default='default')
==============
Web Responsive
==============
.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
.. |badge1| image:: https://img.shields.io/badge/maturity-Production%2FStable-green.png
:target: https://odoo-community.org/page/development-status
:alt: Production/Stable
.. |badge2| image:: https://img.shields.io/badge/licence-LGPL--3-blue.png
:target: http://www.gnu.org/licenses/lgpl-3.0-standalone.html
:alt: License: LGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fweb-lightgray.png?logo=github
:target: https://github.com/OCA/web/tree/14.0/web_responsive
:alt: OCA/web
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/web-14-0/web-14-0-web_responsive
:alt: Translate me on Weblate
.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png
:target: https://runbot.odoo-community.org/runbot/162/14.0
:alt: Try me on Runbot
|badge1| |badge2| |badge3| |badge4| |badge5|
This module adds responsiveness to web backend.
Features for all devices:
* New navigation with an app drawer
.. image:: https://user-images.githubusercontent.com/973709/48417193-09a1e080-e74a-11e8-8a0c-e73eb689b2fb.gif
* Quick menu search from the app drawer
.. image:: https://user-images.githubusercontent.com/973709/48417213-17576600-e74a-11e8-846a-57691e82636b.gif
* Increase the size of the labels in extra large screens
.. image:: https://raw.githubusercontent.com/OCA/web/14.0/web_responsive/static/img/label_size_small.png
.. image:: https://raw.githubusercontent.com/OCA/web/14.0/web_responsive/static/img/label_size_large.png
Features for mobile:
* App-specific submenus are shown on full screen when toggling them from the
"hamburger" menu
.. image:: https://user-images.githubusercontent.com/973709/48417297-51286c80-e74a-11e8-9a47-22c810b18c43.gif
* View type picker dropdown displays confortably
.. image:: https://user-images.githubusercontent.com/973709/50964322-e3d55580-14c6-11e9-8249-48db9539600f.gif
* Top app bar is always visible, but the control panel is hidden when
scrolling down, to save some vaulable vertical space
.. image:: https://user-images.githubusercontent.com/973709/50964496-5cd4ad00-14c7-11e9-9261-fd223a329d02.gif
* Form status bar action and status buttons are collapsed in dropdowns.
Other control panel buttons use icons to save space.
.. image:: https://user-images.githubusercontent.com/973709/50965446-e08f9900-14c9-11e9-92d6-dda472cb6557.gif
* Breadcrumbs navigation is collapsed with a "back arrow" button.
.. image:: https://user-images.githubusercontent.com/973709/50965168-1d0ec500-14c9-11e9-82a0-dfee82ed0861.gif
* Search panel is hidden on small screens.
.. image:: https://raw.githubusercontent.com/OCA/web/14.0/web_responsive/static/img/search_panel.gif
Features for computers:
* Keyboard shortcuts for easier navigation, **using ``Alt + Shift + [key]``**
combination instead of just ``Alt + [key]``.
See https://github.com/odoo/odoo/issues/30068 to understand why.
.. image:: https://user-images.githubusercontent.com/973709/48417578-ff341680-e74a-11e8-8881-017709e912bc.png
* Autofocus on search menu box when opening the drawer
.. image:: https://user-images.githubusercontent.com/973709/48417213-17576600-e74a-11e8-846a-57691e82636b.gif
* Set chatter on the side of the screen, optional per user
.. image:: https://user-images.githubusercontent.com/973709/48417270-41108d00-e74a-11e8-9172-cba825d027ed.gif
* Full width form sheets
.. image:: https://user-images.githubusercontent.com/973709/48417428-ac5a5f00-e74a-11e8-8839-5bc538c54c1d.png
* Sticky chatter topbar
.. image:: https://raw.githubusercontent.com/OCA/web/14.0/web_responsive/static/img/chatter_topbar.gif
* AppMenu waits for action finished to show the view
.. image:: https://raw.githubusercontent.com/OCA/web/14.0/web_responsive/static/img/appmenu.gif
* Sticky header & footer in list view
.. image:: https://raw.githubusercontent.com/OCA/web/14.0/web_responsive/static/img/listview.gif
* Sticky statusbar in form view
.. image:: https://raw.githubusercontent.com/OCA/web/14.0/web_responsive/static/img/formview.gif
* Followers and send button is displayed on mobile. Avatar is hidden.
.. image:: https://raw.githubusercontent.com/OCA/web/14.0/web_responsive/static/img/chatter.gif
* When the chatter is configured on the side part, the document viewer fills that
part for side-by-side reading instead of full screen. You can still put it on full
width preview clicking on the new maximize button.
.. image:: https://raw.githubusercontent.com/OCA/web/14.0/web_responsive/static/img/document_viewer.gif
* Bigger checkboxes in list view
.. image:: https://raw.githubusercontent.com/OCA/web/14.0/web_responsive/static/img/big_checkboxes.gif
* Scrollable dropdowns
.. image:: https://raw.githubusercontent.com/OCA/web/14.0/web_responsive/static/img/dropdown_scroll.gif
**Table of contents**
.. contents::
:local:
Usage
=====
The following keyboard shortcuts are implemented:
* Navigate app search results - Arrow keys
* Choose app result - ``Enter``
* ``Esc`` to close app drawer
Known issues / Roadmap
======================
* To view the full experience in a device, the page must be loaded with the
device screen size. This means that, if you change the size of your browser,
you should reload the web client to get the full experience for that
new size. This is Odoo's own limitation.
* App navigation with keyboard.
* Handle long titles on forms in a better way
* Standard sticky headers seems to not work properly on iOS Safari/Chrome (see #1626).
Bug Tracker
===========
Bugs are tracked on `GitHub Issues <https://github.com/OCA/web/issues>`_.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us smashing it by providing a detailed and welcomed
`feedback <https://github.com/OCA/web/issues/new?body=module:%20web_responsive%0Aversion:%2014.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
Do not contact contributors directly about support or help with technical issues.
Credits
=======
Authors
~~~~~~~
* LasLabs
* Tecnativa
Contributors
~~~~~~~~~~~~
* Dave Lasley <dave@laslabs.com>
* Jairo Llopis <jairo.llopis@tecnativa.com>
* Dennis Sluijk <d.sluijk@onestein.nl>
* Sergio Teruel <sergio.teruel@tecnativa.com>
* Alexandre Díaz <dev@redneboa.es>
* Mathias Markl <mathias.markl@mukit.at>
* Iván Todorovich <ivan.todorovich@gmail.com>
* Sergey Shebanin <sergey@shebanin.ru>
Maintainers
~~~~~~~~~~~
This module is maintained by the OCA.
.. image:: https://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: https://odoo-community.org
OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.
.. |maintainer-Yajo| image:: https://github.com/Yajo.png?size=40px
:target: https://github.com/Yajo
:alt: Yajo
.. |maintainer-Tardo| image:: https://github.com/Tardo.png?size=40px
:target: https://github.com/Tardo
:alt: Tardo
Current `maintainers <https://odoo-community.org/page/maintainer-role>`__:
|maintainer-Yajo| |maintainer-Tardo|
This module is part of the `OCA/web <https://github.com/OCA/web/tree/14.0/web_responsive>`_ project on GitHub.
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
# Copyright 2016-2017 LasLabs Inc.
# Copyright 2017-2018 Tecnativa - Jairo Llopis
# Copyright 2018-2019 Tecnativa - Alexandre Díaz
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
{
"name": "Web Responsive",
"summary": "Responsive web client, community-supported",
"version": "14.0.1.2.0",
"category": "Website",
"website": "https://github.com/OCA/web",
"author": "LasLabs, Tecnativa, " "Odoo Community Association (OCA)",
"license": "LGPL-3",
"installable": True,
"depends": ["web", "mail"],
"development_status": "Production/Stable",
"maintainers": ["Yajo", "Tardo"],
"data": ["views/assets.xml", "views/res_users.xml", "views/web.xml"],
"qweb": [
"static/src/xml/apps.xml",
"static/src/xml/form_buttons.xml",
"static/src/xml/menu.xml",
"static/src/xml/navbar.xml",
"static/src/xml/attachment_viewer.xml",
"static/src/xml/discuss.xml",
"static/src/xml/control_panel.xml",
"static/src/xml/search_panel.xml",
],
"sequence": 1,
}
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * web_responsive
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 13.0\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2020-11-07 15:08+0000\n"
"Last-Translator: Waleed Mohsen <Mohsen.Waleed@gmail.com>\n"
"Language-Team: none\n"
"Language: ar\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 "
"&& n%100<=10 ? 3 : n%100>=11 ? 4 : 5;\n"
"X-Generator: Weblate 3.10\n"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/apps.xml:0
#, python-format
msgid "#menu_id=#{app.menuID}&action_id=#{app.actionID}"
msgstr "#menu_id=#{app.menuID}&action_id=#{app.actionID}"
#. module: web_responsive
#: model:ir.model.fields,field_description:web_responsive.field_res_users__chatter_position
msgid "Chatter Position"
msgstr "موقع الدردشة"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0
#, python-format
msgid "Close"
msgstr "إغلاق"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/form_view.xml:0
#, python-format
msgid "Create"
msgstr "إنشاء"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/form_view.xml:0
#, python-format
msgid "Discard"
msgstr "تجاهل"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/form_view.xml:0
#, python-format
msgid "Edit"
msgstr "تعديل"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0
#, python-format
msgid "Maximize"
msgstr "تكبير"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0
#, python-format
msgid "Minimize"
msgstr "تصغير"
#. module: web_responsive
#: model:ir.model.fields.selection,name:web_responsive.selection__res_users__chatter_position__normal
msgid "Normal"
msgstr "عادي"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/form_view.xml:0
#, python-format
msgid "Quick actions"
msgstr "اجراءات سريعة"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/form_view.xml:0
#, python-format
msgid "Save"
msgstr "حفظ"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/apps.xml:0
#, python-format
msgid "Search menus..."
msgstr "بحث في القوائم..."
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/menu.xml:0
#, python-format
msgid "Shift"
msgstr ""
#. module: web_responsive
#: model:ir.model.fields.selection,name:web_responsive.selection__res_users__chatter_position__sided
msgid "Sided"
msgstr "جانبي"
#. module: web_responsive
#: model:ir.model,name:web_responsive.model_res_users
msgid "Users"
msgstr "المستخدمون"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/discuss.xml:0
#, python-format
msgid ""
"btn btn-secondary o_mail_discuss_button_multi_user_channel d-md-block d-none"
msgstr ""
"btn btn-secondary o_mail_discuss_button_multi_user_channel d-md-block d-none"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/apps.xml:0
#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0
#, python-format
msgid "false"
msgstr "false"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0
#, python-format
msgid "modal o_modal_fullscreen o_document_viewer o_responsive_document_viewer"
msgstr ""
"modal o_modal_fullscreen o_document_viewer o_responsive_document_viewer"
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * web_responsive
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 13.0\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2020-02-02 22:13+0000\n"
"Last-Translator: eduardgm <eduard.garcia@qubiq.es>\n"
"Language-Team: none\n"
"Language: ca\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 3.10\n"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/apps.xml:0
#, python-format
msgid "#menu_id=#{app.menuID}&action_id=#{app.actionID}"
msgstr ""
#. module: web_responsive
#: model:ir.model.fields,field_description:web_responsive.field_res_users__chatter_position
msgid "Chatter Position"
msgstr "Posició del chatter"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0
#, python-format
msgid "Close"
msgstr "Tancar"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/form_view.xml:0
#, python-format
msgid "Create"
msgstr "Crear"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/form_view.xml:0
#, python-format
msgid "Discard"
msgstr "Descartar"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/form_view.xml:0
#, python-format
msgid "Edit"
msgstr "Editar"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0
#, python-format
msgid "Maximize"
msgstr "Maximitzar"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0
#, python-format
msgid "Minimize"
msgstr "Minimitzar"
#. module: web_responsive
#: model:ir.model.fields.selection,name:web_responsive.selection__res_users__chatter_position__normal
msgid "Normal"
msgstr "Normal"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/form_view.xml:0
#, python-format
msgid "Quick actions"
msgstr "Accions ràpides"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/form_view.xml:0
#, python-format
msgid "Save"
msgstr "Guardar"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/apps.xml:0
#, python-format
msgid "Search menus..."
msgstr "Cercar menús..."
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/menu.xml:0
#, python-format
msgid "Shift"
msgstr ""
#. module: web_responsive
#: model:ir.model.fields.selection,name:web_responsive.selection__res_users__chatter_position__sided
msgid "Sided"
msgstr "Lateral"
#. module: web_responsive
#: model:ir.model,name:web_responsive.model_res_users
msgid "Users"
msgstr "Usuaris"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/discuss.xml:0
#, python-format
msgid ""
"btn btn-secondary o_mail_discuss_button_multi_user_channel d-md-block d-none"
msgstr ""
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/apps.xml:0
#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0
#, python-format
msgid "false"
msgstr "fals"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0
#, python-format
msgid "modal o_modal_fullscreen o_document_viewer o_responsive_document_viewer"
msgstr ""
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * web_responsive
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 11.0\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2018-09-02 05:11+0000\n"
"Last-Translator: Hans Henrik Gabelgaard <hhg@gabelgaard.org>\n"
"Language-Team: none\n"
"Language: da\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 3.1.1\n"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/apps.xml:0
#, python-format
msgid "#menu_id=#{app.menuID}&action_id=#{app.actionID}"
msgstr ""
#. module: web_responsive
#: model:ir.model.fields,field_description:web_responsive.field_res_users__chatter_position
msgid "Chatter Position"
msgstr "Log position"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0
#, python-format
msgid "Close"
msgstr ""
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/form_view.xml:0
#, python-format
msgid "Create"
msgstr ""
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/form_view.xml:0
#, python-format
msgid "Discard"
msgstr ""
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/form_view.xml:0
#, python-format
msgid "Edit"
msgstr ""
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0
#, python-format
msgid "Maximize"
msgstr ""
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0
#, python-format
msgid "Minimize"
msgstr ""
#. module: web_responsive
#: model:ir.model.fields.selection,name:web_responsive.selection__res_users__chatter_position__normal
msgid "Normal"
msgstr ""
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/form_view.xml:0
#, python-format
msgid "Quick actions"
msgstr ""
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/form_view.xml:0
#, python-format
msgid "Save"
msgstr ""
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/apps.xml:0
#, python-format
msgid "Search menus..."
msgstr ""
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/menu.xml:0
#, python-format
msgid "Shift"
msgstr ""
#. module: web_responsive
#: model:ir.model.fields.selection,name:web_responsive.selection__res_users__chatter_position__sided
msgid "Sided"
msgstr "Side"
#. module: web_responsive
#: model:ir.model,name:web_responsive.model_res_users
msgid "Users"
msgstr "Brugere"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/discuss.xml:0
#, python-format
msgid ""
"btn btn-secondary o_mail_discuss_button_multi_user_channel d-md-block d-none"
msgstr ""
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/apps.xml:0
#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0
#, python-format
msgid "false"
msgstr ""
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0
#, python-format
msgid "modal o_modal_fullscreen o_document_viewer o_responsive_document_viewer"
msgstr ""
#~ msgid "<span class=\"sr-only\">Toggle App Drawer</span>"
#~ msgstr "<span class=\"sr-only\">Skift App skuffe</span>"
#~ msgid "<span class=\"sr-only\">Toggle Navigation</span>"
#~ msgstr "<span class=\"sr-only\">Skift navigation</span>"
#~ msgid "Apps"
#~ msgstr "Applikationer"
#~ msgid "More"
#~ msgstr "Mere"
#~ msgid "More <b class=\"caret\"/>"
#~ msgstr "Mere <b class=\"caret\"/>"
#~ msgid "Task"
#~ msgstr "Opgave"
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * web_responsive
#
# Translators:
# Niki Waibel <niki.waibel@gmail.com>, 2017
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 10.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-02-03 01:37+0000\n"
"PO-Revision-Date: 2021-02-18 15:45+0000\n"
"Last-Translator: Janik Vonrotz <janikvonrotz@gmail.com>\n"
"Language-Team: German (https://www.transifex.com/oca/teams/23907/de/)\n"
"Language: de\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 4.3.2\n"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/apps.xml:0
#, python-format
msgid "#menu_id=#{app.menuID}&action_id=#{app.actionID}"
msgstr ""
#. module: web_responsive
#: model:ir.model.fields,field_description:web_responsive.field_res_users__chatter_position
msgid "Chatter Position"
msgstr "Chatter-Position"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0
#, python-format
msgid "Close"
msgstr "Schließen"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/form_view.xml:0
#, python-format
msgid "Create"
msgstr "Erstellen"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/form_view.xml:0
#, python-format
msgid "Discard"
msgstr "Verwerfen"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/form_view.xml:0
#, python-format
msgid "Edit"
msgstr "Ändern"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0
#, python-format
msgid "Maximize"
msgstr "maximieren"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0
#, python-format
msgid "Minimize"
msgstr "minimieren"
#. module: web_responsive
#: model:ir.model.fields.selection,name:web_responsive.selection__res_users__chatter_position__normal
msgid "Normal"
msgstr "normal"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/form_view.xml:0
#, python-format
msgid "Quick actions"
msgstr "Schnell-Aktion"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/form_view.xml:0
#, python-format
msgid "Save"
msgstr "Speichern"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/apps.xml:0
#, python-format
msgid "Search menus..."
msgstr "Such-Menü"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/menu.xml:0
#, python-format
msgid "Shift"
msgstr ""
#. module: web_responsive
#: model:ir.model.fields.selection,name:web_responsive.selection__res_users__chatter_position__sided
msgid "Sided"
msgstr "Seitlich"
#. module: web_responsive
#: model:ir.model,name:web_responsive.model_res_users
msgid "Users"
msgstr "Benutzer"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/discuss.xml:0
#, python-format
msgid ""
"btn btn-secondary o_mail_discuss_button_multi_user_channel d-md-block d-none"
msgstr ""
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/apps.xml:0
#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0
#, python-format
msgid "false"
msgstr ""
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0
#, python-format
msgid "modal o_modal_fullscreen o_document_viewer o_responsive_document_viewer"
msgstr ""
#~ msgid "<span class=\"sr-only\">Toggle App Drawer</span>"
#~ msgstr "<span class=\"sr-only\">App Ordner umschalten</span>"
#~ msgid "<span class=\"sr-only\">Toggle Navigation</span>"
#~ msgstr "<span class=\"sr-only\">Navigation umschalten</span>"
#~ msgid "Apps"
#~ msgstr "Apps"
#~ msgid "More <b class=\"caret\"/>"
#~ msgstr "Mehr <b class=\"caret\"/>"
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * web_responsive
#
# Translators:
# Pedro M. Baeza <pedro.baeza@gmail.com>, 2016
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 10.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-01-10 10:49+0000\n"
"PO-Revision-Date: 2021-02-17 14:45+0000\n"
"Last-Translator: claudiagn <claudia.gargallo@qubiq.es>\n"
"Language-Team: Spanish (https://www.transifex.com/oca/teams/23907/es/)\n"
"Language: es\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 4.3.2\n"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/apps.xml:0
#, python-format
msgid "#menu_id=#{app.menuID}&action_id=#{app.actionID}"
msgstr "#menu_id=#{app.menuID}&action_id=#{app.actionID}"
#. module: web_responsive
#: model:ir.model.fields,field_description:web_responsive.field_res_users__chatter_position
msgid "Chatter Position"
msgstr "Posición del chatter"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0
#, python-format
msgid "Close"
msgstr "Cerrar"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/form_view.xml:0
#, python-format
msgid "Create"
msgstr "Crear"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/form_view.xml:0
#, python-format
msgid "Discard"
msgstr "Descartar"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/form_view.xml:0
#, python-format
msgid "Edit"
msgstr "Editar"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0
#, python-format
msgid "Maximize"
msgstr "Maximizar"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0
#, python-format
msgid "Minimize"
msgstr "Minimizar"
#. module: web_responsive
#: model:ir.model.fields.selection,name:web_responsive.selection__res_users__chatter_position__normal
msgid "Normal"
msgstr "Normal"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/form_view.xml:0
#, python-format
msgid "Quick actions"
msgstr "Acciones rápidas"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/form_view.xml:0
#, python-format
msgid "Save"
msgstr "Guardar"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/apps.xml:0
#, python-format
msgid "Search menus..."
msgstr "Buscar menús..."
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/menu.xml:0
#, python-format
msgid "Shift"
msgstr "Turno"
#. module: web_responsive
#: model:ir.model.fields.selection,name:web_responsive.selection__res_users__chatter_position__sided
msgid "Sided"
msgstr "Lateral"
#. module: web_responsive
#: model:ir.model,name:web_responsive.model_res_users
msgid "Users"
msgstr "Usuarios"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/discuss.xml:0
#, python-format
msgid ""
"btn btn-secondary o_mail_discuss_button_multi_user_channel d-md-block d-none"
msgstr ""
"btn btn-secondary o_mail_discuss_button_multi_user_channel d-md-block d-none"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/apps.xml:0
#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0
#, python-format
msgid "false"
msgstr "falso"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0
#, python-format
msgid "modal o_modal_fullscreen o_document_viewer o_responsive_document_viewer"
msgstr "modal o_modal_fullscreen o_document_viewer o_responsive_document_viewer"
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * web_responsive
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 14.0\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2021-09-23 07:34+0000\n"
"Last-Translator: Saeed Raeisi <saeed.raesi2020@gmail.com>\n"
"Language-Team: none\n"
"Language: fa\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: nplurals=2; plural=n > 1;\n"
"X-Generator: Weblate 4.3.2\n"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/search_panel.xml:0
#, python-format
msgid "All"
msgstr "همه"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/control_panel.xml:0
#, python-format
msgid "CLEAR"
msgstr "پاک کردن"
#. module: web_responsive
#: model:ir.model.fields,field_description:web_responsive.field_res_users__chatter_position
msgid "Chatter Position"
msgstr "موقعیت چت باکس"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/form_buttons.xml:0
#: code:addons/web_responsive/static/src/xml/form_buttons.xml:0
#, python-format
msgid "Create"
msgstr "ایجاد"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/form_buttons.xml:0
#: code:addons/web_responsive/static/src/xml/form_buttons.xml:0
#, python-format
msgid "Discard"
msgstr "لغو"
#. module: web_responsive
#: model:ir.model.fields,field_description:web_responsive.field_res_users__display_name
msgid "Display Name"
msgstr "نام نمایشی"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/form_buttons.xml:0
#, python-format
msgid "Edit"
msgstr "ویرایش"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/control_panel.xml:0
#: code:addons/web_responsive/static/src/xml/search_panel.xml:0
#, python-format
msgid "FILTER"
msgstr "فیلتر"
#. module: web_responsive
#: model:ir.model.fields,field_description:web_responsive.field_res_users__id
msgid "ID"
msgstr "شناسه"
#. module: web_responsive
#: model:ir.model.fields,field_description:web_responsive.field_res_users____last_update
msgid "Last Modified on"
msgstr "آخرین ویرایش در"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/attachment_viewer.xml:0
#: code:addons/web_responsive/static/src/xml/attachment_viewer.xml:0
#, python-format
msgid "Maximize"
msgstr "بزرگ کردن"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/attachment_viewer.xml:0
#: code:addons/web_responsive/static/src/xml/attachment_viewer.xml:0
#, python-format
msgid "Minimize"
msgstr "کوچک کردن"
#. module: web_responsive
#: model:ir.model.fields.selection,name:web_responsive.selection__res_users__chatter_position__normal
msgid "Normal"
msgstr "عادی"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/form_buttons.xml:0
#, python-format
msgid "Quick actions"
msgstr "اقدامات سریع"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/control_panel.xml:0
#: code:addons/web_responsive/static/src/xml/search_panel.xml:0
#, python-format
msgid "SEE RESULT"
msgstr "مشاهده نتیجه"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/form_buttons.xml:0
#: code:addons/web_responsive/static/src/xml/form_buttons.xml:0
#, python-format
msgid "Save"
msgstr "ذخیره"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/apps.xml:0
#, python-format
msgid "Search menus..."
msgstr "جستجو در منو..."
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/control_panel.xml:0
#: code:addons/web_responsive/static/src/xml/control_panel.xml:0
#, python-format
msgid "Search..."
msgstr "جستجو..."
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/menu.xml:0
#, python-format
msgid "Shift"
msgstr "شیفت"
#. module: web_responsive
#: model:ir.model.fields.selection,name:web_responsive.selection__res_users__chatter_position__sided
msgid "Sided"
msgstr "طرف"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/form_buttons.xml:0
#, python-format
msgid "Today"
msgstr "امروز"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/js/kanban_renderer_mobile.js:0
#, python-format
msgid "Undefined"
msgstr "تعریف نشده"
#. module: web_responsive
#: model:ir.model,name:web_responsive.model_res_users
msgid "Users"
msgstr "کاربران"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/control_panel.xml:0
#, python-format
msgid "View switcher"
msgstr "تعویض کننده نما"
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * web_responsive
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 14.0\n"
"Report-Msgid-Bugs-To: \n"
"Last-Translator: Automatically generated\n"
"Language-Team: none\n"
"Language: fa_IR\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: nplurals=2; plural=n > 1;\n"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/search_panel.xml:0
#, python-format
msgid "All"
msgstr ""
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/control_panel.xml:0
#, python-format
msgid "CLEAR"
msgstr ""
#. module: web_responsive
#: model:ir.model.fields,field_description:web_responsive.field_res_users__chatter_position
msgid "Chatter Position"
msgstr ""
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/form_buttons.xml:0
#: code:addons/web_responsive/static/src/xml/form_buttons.xml:0
#, python-format
msgid "Create"
msgstr ""
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/form_buttons.xml:0
#: code:addons/web_responsive/static/src/xml/form_buttons.xml:0
#, python-format
msgid "Discard"
msgstr ""
#. module: web_responsive
#: model:ir.model.fields,field_description:web_responsive.field_res_users__display_name
msgid "Display Name"
msgstr ""
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/form_buttons.xml:0
#, python-format
msgid "Edit"
msgstr ""
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/control_panel.xml:0
#: code:addons/web_responsive/static/src/xml/search_panel.xml:0
#, python-format
msgid "FILTER"
msgstr ""
#. module: web_responsive
#: model:ir.model.fields,field_description:web_responsive.field_res_users__id
msgid "ID"
msgstr ""
#. module: web_responsive
#: model:ir.model.fields,field_description:web_responsive.field_res_users____last_update
msgid "Last Modified on"
msgstr ""
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/attachment_viewer.xml:0
#: code:addons/web_responsive/static/src/xml/attachment_viewer.xml:0
#, python-format
msgid "Maximize"
msgstr ""
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/attachment_viewer.xml:0
#: code:addons/web_responsive/static/src/xml/attachment_viewer.xml:0
#, python-format
msgid "Minimize"
msgstr ""
#. module: web_responsive
#: model:ir.model.fields.selection,name:web_responsive.selection__res_users__chatter_position__normal
msgid "Normal"
msgstr ""
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/form_buttons.xml:0
#, python-format
msgid "Quick actions"
msgstr ""
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/control_panel.xml:0
#: code:addons/web_responsive/static/src/xml/search_panel.xml:0
#, python-format
msgid "SEE RESULT"
msgstr ""
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/form_buttons.xml:0
#: code:addons/web_responsive/static/src/xml/form_buttons.xml:0
#, python-format
msgid "Save"
msgstr ""
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/apps.xml:0
#, python-format
msgid "Search menus..."
msgstr ""
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/control_panel.xml:0
#: code:addons/web_responsive/static/src/xml/control_panel.xml:0
#, python-format
msgid "Search..."
msgstr ""
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/menu.xml:0
#, python-format
msgid "Shift"
msgstr ""
#. module: web_responsive
#: model:ir.model.fields.selection,name:web_responsive.selection__res_users__chatter_position__sided
msgid "Sided"
msgstr ""
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/form_buttons.xml:0
#, python-format
msgid "Today"
msgstr ""
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/js/kanban_renderer_mobile.js:0
#, python-format
msgid "Undefined"
msgstr ""
#. module: web_responsive
#: model:ir.model,name:web_responsive.model_res_users
msgid "Users"
msgstr ""
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/control_panel.xml:0
#, python-format
msgid "View switcher"
msgstr ""
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * web_responsive
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 12.0\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2021-09-25 08:34+0000\n"
"Last-Translator: Rémi <remi@le-filament.com>\n"
"Language-Team: none\n"
"Language: fr\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: nplurals=2; plural=n > 1;\n"
"X-Generator: Weblate 4.3.2\n"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/apps.xml:0
#, python-format
msgid "#menu_id=#{app.menuID}&action_id=#{app.actionID}"
msgstr "#menu_id=#{app.menuID}&action_id=#{app.actionID}"
#. module: web_responsive
#: model:ir.model.fields,field_description:web_responsive.field_res_users__chatter_position
msgid "Chatter Position"
msgstr "Position du Chatter"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0
#, python-format
msgid "Close"
msgstr "Fermer"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/form_view.xml:0
#, python-format
msgid "Create"
msgstr "Créer"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/form_view.xml:0
#, python-format
msgid "Discard"
msgstr "Annuler"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/form_view.xml:0
#, python-format
msgid "Edit"
msgstr "Modifier"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0
#, python-format
msgid "Maximize"
msgstr "Maximiser"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0
#, python-format
msgid "Minimize"
msgstr "Minimiser"
#. module: web_responsive
#: model:ir.model.fields.selection,name:web_responsive.selection__res_users__chatter_position__normal
msgid "Normal"
msgstr "Normal"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/form_view.xml:0
#, python-format
msgid "Quick actions"
msgstr "Actions rapides"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/form_view.xml:0
#, python-format
msgid "Save"
msgstr "Sauvegarder"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/apps.xml:0
#, python-format
msgid "Search menus..."
msgstr "Rechercher dans les menus..."
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/menu.xml:0
#, fuzzy, python-format
msgid "Shift"
msgstr "Shift"
#. module: web_responsive
#: model:ir.model.fields.selection,name:web_responsive.selection__res_users__chatter_position__sided
msgid "Sided"
msgstr "À coté"
#. module: web_responsive
#: model:ir.model,name:web_responsive.model_res_users
msgid "Users"
msgstr "Utilisateurs"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/discuss.xml:0
#, python-format
msgid ""
"btn btn-secondary o_mail_discuss_button_multi_user_channel d-md-block d-none"
msgstr ""
"btn btn-secondary o_mail_discuss_button_multi_user_channel d-md-block d-none"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/apps.xml:0
#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0
#, fuzzy, python-format
msgid "false"
msgstr "false"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0
#, python-format
msgid "modal o_modal_fullscreen o_document_viewer o_responsive_document_viewer"
msgstr "modal o_modal_fullscreen o_document_viewer o_responsive_document_viewer"
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * web_responsive
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 14.0\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2021-04-11 18:46+0000\n"
"Last-Translator: Yves Le Doeuff <yld@alliasys.fr>\n"
"Language-Team: none\n"
"Language: fr_FR\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: nplurals=2; plural=n > 1;\n"
"X-Generator: Weblate 4.3.2\n"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/search_panel.xml:0
#, python-format
msgid "All"
msgstr ""
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/control_panel.xml:0
#, python-format
msgid "CLEAR"
msgstr ""
#. module: web_responsive
#: model:ir.model.fields,field_description:web_responsive.field_res_users__chatter_position
msgid "Chatter Position"
msgstr "Position du Chatter"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/form_buttons.xml:0
#: code:addons/web_responsive/static/src/xml/form_buttons.xml:0
#, python-format
msgid "Create"
msgstr "Créer"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/form_buttons.xml:0
#: code:addons/web_responsive/static/src/xml/form_buttons.xml:0
#, python-format
msgid "Discard"
msgstr "Annuler"
#. module: web_responsive
#: model:ir.model.fields,field_description:web_responsive.field_res_users__display_name
msgid "Display Name"
msgstr ""
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/form_buttons.xml:0
#, python-format
msgid "Edit"
msgstr "Editer"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/control_panel.xml:0
#: code:addons/web_responsive/static/src/xml/search_panel.xml:0
#, python-format
msgid "FILTER"
msgstr ""
#. module: web_responsive
#: model:ir.model.fields,field_description:web_responsive.field_res_users__id
msgid "ID"
msgstr ""
#. module: web_responsive
#: model:ir.model.fields,field_description:web_responsive.field_res_users____last_update
msgid "Last Modified on"
msgstr ""
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/attachment_viewer.xml:0
#: code:addons/web_responsive/static/src/xml/attachment_viewer.xml:0
#, python-format
msgid "Maximize"
msgstr "Maximiser"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/attachment_viewer.xml:0
#: code:addons/web_responsive/static/src/xml/attachment_viewer.xml:0
#, python-format
msgid "Minimize"
msgstr "Minimiser"
#. module: web_responsive
#: model:ir.model.fields.selection,name:web_responsive.selection__res_users__chatter_position__normal
msgid "Normal"
msgstr "Normal"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/form_buttons.xml:0
#, python-format
msgid "Quick actions"
msgstr "Actions rapides"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/control_panel.xml:0
#: code:addons/web_responsive/static/src/xml/search_panel.xml:0
#, python-format
msgid "SEE RESULT"
msgstr ""
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/form_buttons.xml:0
#: code:addons/web_responsive/static/src/xml/form_buttons.xml:0
#, python-format
msgid "Save"
msgstr "Sauvegarder"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/apps.xml:0
#, python-format
msgid "Search menus..."
msgstr "Rechercher dans les menus..."
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/control_panel.xml:0
#: code:addons/web_responsive/static/src/xml/control_panel.xml:0
#, python-format
msgid "Search..."
msgstr ""
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/menu.xml:0
#, python-format
msgid "Shift"
msgstr ""
#. module: web_responsive
#: model:ir.model.fields.selection,name:web_responsive.selection__res_users__chatter_position__sided
msgid "Sided"
msgstr "À coté"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/form_buttons.xml:0
#, python-format
msgid "Today"
msgstr ""
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/js/kanban_renderer_mobile.js:0
#, python-format
msgid "Undefined"
msgstr ""
#. module: web_responsive
#: model:ir.model,name:web_responsive.model_res_users
msgid "Users"
msgstr "Utilisateurs"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/control_panel.xml:0
#, python-format
msgid "View switcher"
msgstr ""
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * web_responsive
#
# Translators:
# Bole <bole@dajmi5.com>, 2017
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 10.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-04-28 18:03+0000\n"
"PO-Revision-Date: 2017-04-28 18:03+0000\n"
"Last-Translator: Bole <bole@dajmi5.com>, 2017\n"
"Language-Team: Croatian (https://www.transifex.com/oca/teams/23907/hr/)\n"
"Language: hr\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/apps.xml:0
#, python-format
msgid "#menu_id=#{app.menuID}&action_id=#{app.actionID}"
msgstr ""
#. module: web_responsive
#: model:ir.model.fields,field_description:web_responsive.field_res_users__chatter_position
msgid "Chatter Position"
msgstr ""
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0
#, python-format
msgid "Close"
msgstr ""
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/form_view.xml:0
#, python-format
msgid "Create"
msgstr ""
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/form_view.xml:0
#, python-format
msgid "Discard"
msgstr ""
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/form_view.xml:0
#, python-format
msgid "Edit"
msgstr ""
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0
#, python-format
msgid "Maximize"
msgstr ""
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0
#, python-format
msgid "Minimize"
msgstr ""
#. module: web_responsive
#: model:ir.model.fields.selection,name:web_responsive.selection__res_users__chatter_position__normal
msgid "Normal"
msgstr ""
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/form_view.xml:0
#, python-format
msgid "Quick actions"
msgstr ""
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/form_view.xml:0
#, python-format
msgid "Save"
msgstr ""
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/apps.xml:0
#, python-format
msgid "Search menus..."
msgstr ""
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/menu.xml:0
#, python-format
msgid "Shift"
msgstr ""
#. module: web_responsive
#: model:ir.model.fields.selection,name:web_responsive.selection__res_users__chatter_position__sided
msgid "Sided"
msgstr ""
#. module: web_responsive
#: model:ir.model,name:web_responsive.model_res_users
msgid "Users"
msgstr ""
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/discuss.xml:0
#, python-format
msgid ""
"btn btn-secondary o_mail_discuss_button_multi_user_channel d-md-block d-none"
msgstr ""
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/apps.xml:0
#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0
#, python-format
msgid "false"
msgstr ""
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0
#, python-format
msgid "modal o_modal_fullscreen o_document_viewer o_responsive_document_viewer"
msgstr ""
#~ msgid "<span class=\"sr-only\">Toggle App Drawer</span>"
#~ msgstr "<span class=\"sr-only\">Izmjeni izbornik aplikacije</span>"
#~ msgid "<span class=\"sr-only\">Toggle Navigation</span>"
#~ msgstr "<span class=\"sr-only\">Izmjeni navigaciju</span>"
#~ msgid "Apps"
#~ msgstr "Apikacije"
#~ msgid "More <b class=\"caret\"/>"
#~ msgstr "Više <b class=\"caret\"/>"
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * web_responsive
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 13.0\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2021-05-17 20:47+0000\n"
"Last-Translator: Bosd <c5e2fd43-d292-4c90-9d1f-74ff3436329a@anonaddy.me>\n"
"Language-Team: none\n"
"Language: nl\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 4.3.2\n"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/apps.xml:0
#, python-format
msgid "#menu_id=#{app.menuID}&action_id=#{app.actionID}"
msgstr "#menu_id=#{app.menuID}&action_id=#{app.actionID}"
#. module: web_responsive
#: model:ir.model.fields,field_description:web_responsive.field_res_users__chatter_position
msgid "Chatter Position"
msgstr "Chatter Positie"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0
#, python-format
msgid "Close"
msgstr "Sluit"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/form_view.xml:0
#, python-format
msgid "Create"
msgstr "Aanmaken"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/form_view.xml:0
#, python-format
msgid "Discard"
msgstr "Negeren"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/form_view.xml:0
#, python-format
msgid "Edit"
msgstr "Bewerken"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0
#, python-format
msgid "Maximize"
msgstr "Maximaliseren"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0
#, python-format
msgid "Minimize"
msgstr "Minimaliseren"
#. module: web_responsive
#: model:ir.model.fields.selection,name:web_responsive.selection__res_users__chatter_position__normal
msgid "Normal"
msgstr "Normaal"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/form_view.xml:0
#, python-format
msgid "Quick actions"
msgstr "Snelle Acties"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/form_view.xml:0
#, python-format
msgid "Save"
msgstr "Opslaan"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/apps.xml:0
#, python-format
msgid "Search menus..."
msgstr "Zoek menu's..."
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/menu.xml:0
#, fuzzy, python-format
msgid "Shift"
msgstr "Shift"
#. module: web_responsive
#: model:ir.model.fields.selection,name:web_responsive.selection__res_users__chatter_position__sided
msgid "Sided"
msgstr "Aan de zijkant"
#. module: web_responsive
#: model:ir.model,name:web_responsive.model_res_users
msgid "Users"
msgstr "Gebruikers"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/discuss.xml:0
#, python-format
msgid ""
"btn btn-secondary o_mail_discuss_button_multi_user_channel d-md-block d-none"
msgstr ""
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/apps.xml:0
#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0
#, fuzzy, python-format
msgid "false"
msgstr "false"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0
#, python-format
msgid "modal o_modal_fullscreen o_document_viewer o_responsive_document_viewer"
msgstr ""
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * web_responsive
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 12.0\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2019-08-12 11:44+0000\n"
"Last-Translator: Pedro Castro Silva <pedrocs@exo.pt>\n"
"Language-Team: none\n"
"Language: pt\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: nplurals=2; plural=n > 1;\n"
"X-Generator: Weblate 3.7.1\n"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/apps.xml:0
#, python-format
msgid "#menu_id=#{app.menuID}&action_id=#{app.actionID}"
msgstr ""
#. module: web_responsive
#: model:ir.model.fields,field_description:web_responsive.field_res_users__chatter_position
msgid "Chatter Position"
msgstr "Posição do Chatter"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0
#, python-format
msgid "Close"
msgstr ""
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/form_view.xml:0
#, python-format
msgid "Create"
msgstr "Criar"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/form_view.xml:0
#, python-format
msgid "Discard"
msgstr "Descartar"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/form_view.xml:0
#, python-format
msgid "Edit"
msgstr "Editar"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0
#, python-format
msgid "Maximize"
msgstr ""
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0
#, python-format
msgid "Minimize"
msgstr ""
#. module: web_responsive
#: model:ir.model.fields.selection,name:web_responsive.selection__res_users__chatter_position__normal
msgid "Normal"
msgstr "Normal"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/form_view.xml:0
#, python-format
msgid "Quick actions"
msgstr "Ações rápidas"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/form_view.xml:0
#, python-format
msgid "Save"
msgstr "Gravar"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/apps.xml:0
#, python-format
msgid "Search menus..."
msgstr "Procurar menus..."
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/menu.xml:0
#, python-format
msgid "Shift"
msgstr ""
#. module: web_responsive
#: model:ir.model.fields.selection,name:web_responsive.selection__res_users__chatter_position__sided
msgid "Sided"
msgstr "Lateralizado"
#. module: web_responsive
#: model:ir.model,name:web_responsive.model_res_users
msgid "Users"
msgstr "Utilizadores"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/discuss.xml:0
#, python-format
msgid ""
"btn btn-secondary o_mail_discuss_button_multi_user_channel d-md-block d-none"
msgstr ""
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/apps.xml:0
#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0
#, python-format
msgid "false"
msgstr ""
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0
#, python-format
msgid "modal o_modal_fullscreen o_document_viewer o_responsive_document_viewer"
msgstr ""
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * web_responsive
#
# Translators:
# Rodrigo de Almeida Sottomaior Macedo <rmsolucoeseminformatic4@gmail.com>, 2017
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 10.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-06-22 08:27+0000\n"
"PO-Revision-Date: 2020-03-21 21:13+0000\n"
"Last-Translator: Rodrigo Macedo <rmsolucoeseminformatic4@gmail.com>\n"
"Language-Team: Portuguese (Brazil) (https://www.transifex.com/oca/"
"teams/23907/pt_BR/)\n"
"Language: pt_BR\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: nplurals=2; plural=n > 1;\n"
"X-Generator: Weblate 3.10\n"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/apps.xml:0
#, python-format
msgid "#menu_id=#{app.menuID}&action_id=#{app.actionID}"
msgstr "#menu_id=#{app.menuID}&action_id=#{app.actionID}"
#. module: web_responsive
#: model:ir.model.fields,field_description:web_responsive.field_res_users__chatter_position
msgid "Chatter Position"
msgstr "Posição do Chatter"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0
#, python-format
msgid "Close"
msgstr "Fechar"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/form_view.xml:0
#, python-format
msgid "Create"
msgstr "Criar"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/form_view.xml:0
#, python-format
msgid "Discard"
msgstr "Descartar"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/form_view.xml:0
#, python-format
msgid "Edit"
msgstr "Editar"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0
#, python-format
msgid "Maximize"
msgstr "Maximizar"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0
#, python-format
msgid "Minimize"
msgstr "Minimizar"
#. module: web_responsive
#: model:ir.model.fields.selection,name:web_responsive.selection__res_users__chatter_position__normal
msgid "Normal"
msgstr "Normal"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/form_view.xml:0
#, python-format
msgid "Quick actions"
msgstr "Ações rápidas"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/form_view.xml:0
#, python-format
msgid "Save"
msgstr "Salvar"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/apps.xml:0
#, python-format
msgid "Search menus..."
msgstr "Pesquisar menus..."
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/menu.xml:0
#, python-format
msgid "Shift"
msgstr ""
#. module: web_responsive
#: model:ir.model.fields.selection,name:web_responsive.selection__res_users__chatter_position__sided
msgid "Sided"
msgstr "Frente e verso"
#. module: web_responsive
#: model:ir.model,name:web_responsive.model_res_users
msgid "Users"
msgstr "Usuários"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/discuss.xml:0
#, python-format
msgid ""
"btn btn-secondary o_mail_discuss_button_multi_user_channel d-md-block d-none"
msgstr ""
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/apps.xml:0
#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0
#, python-format
msgid "false"
msgstr "falso"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0
#, python-format
msgid "modal o_modal_fullscreen o_document_viewer o_responsive_document_viewer"
msgstr ""
"modal o_modal_fullscreen o_document_viewer o_responsive_document_viewer"
#~ msgid "<span class=\"sr-only\">Toggle App Drawer</span>"
#~ msgstr "<span class=\"sr-only\">Aplicativo Desenhador Alternativo</span>"
#~ msgid "<span class=\"sr-only\">Toggle Navigation</span>"
#~ msgstr "<span class=\"sr-only\">Navegação Alternativa</span>"
#~ msgid "Apps"
#~ msgstr "Aplicativos"
#~ msgid "HTTP routing"
#~ msgstr "roteamento HTTP"
#~ msgid "More <b class=\"caret\"/>"
#~ msgstr "Mais <b class=\"caret\"/>"
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * web_responsive
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 14.0\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2021-03-31 16:36+0000\n"
"Last-Translator: SplashS <sergey@shebanin.ru>\n"
"Language-Team: none\n"
"Language: ru\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
"X-Generator: Weblate 4.3.2\n"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/search_panel.xml:0
#, python-format
msgid "All"
msgstr "Все"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/control_panel.xml:0
#, python-format
msgid "CLEAR"
msgstr "Очистить"
#. module: web_responsive
#: model:ir.model.fields,field_description:web_responsive.field_res_users__chatter_position
msgid "Chatter Position"
msgstr "Расположение Чата"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/form_buttons.xml:0
#: code:addons/web_responsive/static/src/xml/form_buttons.xml:0
#, python-format
msgid "Create"
msgstr "Создать"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/form_buttons.xml:0
#: code:addons/web_responsive/static/src/xml/form_buttons.xml:0
#, python-format
msgid "Discard"
msgstr "Отменить"
#. module: web_responsive
#: model:ir.model.fields,field_description:web_responsive.field_res_users__display_name
msgid "Display Name"
msgstr "Видимое имя"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/form_buttons.xml:0
#, python-format
msgid "Edit"
msgstr "Править"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/control_panel.xml:0
#: code:addons/web_responsive/static/src/xml/search_panel.xml:0
#, python-format
msgid "FILTER"
msgstr "Фильтр"
#. module: web_responsive
#: model:ir.model.fields,field_description:web_responsive.field_res_users__id
msgid "ID"
msgstr ""
#. module: web_responsive
#: model:ir.model.fields,field_description:web_responsive.field_res_users____last_update
msgid "Last Modified on"
msgstr ""
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/attachment_viewer.xml:0
#: code:addons/web_responsive/static/src/xml/attachment_viewer.xml:0
#, python-format
msgid "Maximize"
msgstr "Увеличить"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/attachment_viewer.xml:0
#: code:addons/web_responsive/static/src/xml/attachment_viewer.xml:0
#, python-format
msgid "Minimize"
msgstr "Уменьшить"
#. module: web_responsive
#: model:ir.model.fields.selection,name:web_responsive.selection__res_users__chatter_position__normal
msgid "Normal"
msgstr "Снизу"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/form_buttons.xml:0
#, python-format
msgid "Quick actions"
msgstr "Действия"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/control_panel.xml:0
#: code:addons/web_responsive/static/src/xml/search_panel.xml:0
#, python-format
msgid "SEE RESULT"
msgstr "Применить"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/form_buttons.xml:0
#: code:addons/web_responsive/static/src/xml/form_buttons.xml:0
#, python-format
msgid "Save"
msgstr "Сохранить"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/apps.xml:0
#, python-format
msgid "Search menus..."
msgstr "Поиск по меню..."
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/control_panel.xml:0
#: code:addons/web_responsive/static/src/xml/control_panel.xml:0
#, python-format
msgid "Search..."
msgstr "Поиск..."
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/menu.xml:0
#, python-format
msgid "Shift"
msgstr ""
#. module: web_responsive
#: model:ir.model.fields.selection,name:web_responsive.selection__res_users__chatter_position__sided
msgid "Sided"
msgstr "Справа"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/form_buttons.xml:0
#, python-format
msgid "Today"
msgstr "Сегодня"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/js/kanban_renderer_mobile.js:0
#, python-format
msgid "Undefined"
msgstr "Не определено"
#. module: web_responsive
#: model:ir.model,name:web_responsive.model_res_users
msgid "Users"
msgstr "Пользователи"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/control_panel.xml:0
#, python-format
msgid "View switcher"
msgstr "Сменить вид"
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * web_responsive
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 12.0\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2020-07-08 05:19+0000\n"
"Last-Translator: 黎伟杰 <674416404@qq.com>\n"
"Language-Team: none\n"
"Language: zh_CN\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: nplurals=1; plural=0;\n"
"X-Generator: Weblate 3.10\n"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/apps.xml:0
#, python-format
msgid "#menu_id=#{app.menuID}&action_id=#{app.actionID}"
msgstr "#menu_id=#{app.menuID}&action_id=#{app.actionID}"
#. module: web_responsive
#: model:ir.model.fields,field_description:web_responsive.field_res_users__chatter_position
msgid "Chatter Position"
msgstr "聊天位置"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0
#, python-format
msgid "Close"
msgstr "关闭"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/form_view.xml:0
#, python-format
msgid "Create"
msgstr "创建"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/form_view.xml:0
#, python-format
msgid "Discard"
msgstr "丢弃"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/form_view.xml:0
#, python-format
msgid "Edit"
msgstr "编辑"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0
#, python-format
msgid "Maximize"
msgstr "最大化"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0
#, python-format
msgid "Minimize"
msgstr "最小化"
#. module: web_responsive
#: model:ir.model.fields.selection,name:web_responsive.selection__res_users__chatter_position__normal
msgid "Normal"
msgstr "正常"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/form_view.xml:0
#, python-format
msgid "Quick actions"
msgstr "快捷方式"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/form_view.xml:0
#, python-format
msgid "Save"
msgstr "保存"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/apps.xml:0
#, python-format
msgid "Search menus..."
msgstr "搜索菜单..."
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/menu.xml:0
#, python-format
msgid "Shift"
msgstr ""
#. module: web_responsive
#: model:ir.model.fields.selection,name:web_responsive.selection__res_users__chatter_position__sided
msgid "Sided"
msgstr "侧面"
#. module: web_responsive
#: model:ir.model,name:web_responsive.model_res_users
msgid "Users"
msgstr "用户"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/discuss.xml:0
#, python-format
msgid ""
"btn btn-secondary o_mail_discuss_button_multi_user_channel d-md-block d-none"
msgstr ""
"btn btn-secondary o_mail_discuss_button_multi_user_channel d-md-block d-none"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/apps.xml:0
#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0
#, python-format
msgid "false"
msgstr "false"
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0
#, python-format
msgid "modal o_modal_fullscreen o_document_viewer o_responsive_document_viewer"
msgstr ""
"modal o_modal_fullscreen o_document_viewer o_responsive_document_viewer"
# Copyright 2018-2019 Alexandre Díaz
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import fields, models
class ResUsers(models.Model):
_inherit = "res.users"
chatter_position = fields.Selection(
[("normal", "Normal"), ("sided", "Sided")],
string="Chatter Position",
default="sided",
)
def __init__(self, pool, cr):
"""Override of __init__ to add access rights.
Access rights are disabled by default, but allowed on some specific
fields defined in self.SELF_{READ/WRITE}ABLE_FIELDS.
"""
super().__init__(pool, cr)
# duplicate list to avoid modifying the original reference
type(self).SELF_WRITEABLE_FIELDS = list(self.SELF_WRITEABLE_FIELDS)
type(self).SELF_WRITEABLE_FIELDS.extend(["chatter_position"])
# duplicate list to avoid modifying the original reference
type(self).SELF_READABLE_FIELDS = list(self.SELF_READABLE_FIELDS)
type(self).SELF_READABLE_FIELDS.extend(["chatter_position"])
* Dave Lasley <dave@laslabs.com>
* Jairo Llopis <jairo.llopis@tecnativa.com>
* Dennis Sluijk <d.sluijk@onestein.nl>
* Sergio Teruel <sergio.teruel@tecnativa.com>
* Alexandre Díaz <dev@redneboa.es>
* Mathias Markl <mathias.markl@mukit.at>
* Iván Todorovich <ivan.todorovich@gmail.com>
* Sergey Shebanin <sergey@shebanin.ru>
This module adds responsiveness to web backend.
Features for all devices:
* New navigation with an app drawer
.. image:: https://user-images.githubusercontent.com/973709/48417193-09a1e080-e74a-11e8-8a0c-e73eb689b2fb.gif
* Quick menu search from the app drawer
.. image:: https://user-images.githubusercontent.com/973709/48417213-17576600-e74a-11e8-846a-57691e82636b.gif
* Increase the size of the labels in extra large screens
.. image:: ../static/img/label_size_small.png
.. image:: ../static/img/label_size_large.png
Features for mobile:
* App-specific submenus are shown on full screen when toggling them from the
"hamburger" menu
.. image:: https://user-images.githubusercontent.com/973709/48417297-51286c80-e74a-11e8-9a47-22c810b18c43.gif
* View type picker dropdown displays confortably
.. image:: https://user-images.githubusercontent.com/973709/50964322-e3d55580-14c6-11e9-8249-48db9539600f.gif
* Top app bar is always visible, but the control panel is hidden when
scrolling down, to save some vaulable vertical space
.. image:: https://user-images.githubusercontent.com/973709/50964496-5cd4ad00-14c7-11e9-9261-fd223a329d02.gif
* Form status bar action and status buttons are collapsed in dropdowns.
Other control panel buttons use icons to save space.
.. image:: https://user-images.githubusercontent.com/973709/50965446-e08f9900-14c9-11e9-92d6-dda472cb6557.gif
* Breadcrumbs navigation is collapsed with a "back arrow" button.
.. image:: https://user-images.githubusercontent.com/973709/50965168-1d0ec500-14c9-11e9-82a0-dfee82ed0861.gif
* Search panel is hidden on small screens.
.. image:: ../static/img/search_panel.gif
Features for computers:
* Keyboard shortcuts for easier navigation, **using ``Alt + Shift + [key]``**
combination instead of just ``Alt + [key]``.
See https://github.com/odoo/odoo/issues/30068 to understand why.
.. image:: https://user-images.githubusercontent.com/973709/48417578-ff341680-e74a-11e8-8881-017709e912bc.png
* Autofocus on search menu box when opening the drawer
.. image:: https://user-images.githubusercontent.com/973709/48417213-17576600-e74a-11e8-846a-57691e82636b.gif
* Set chatter on the side of the screen, optional per user
.. image:: https://user-images.githubusercontent.com/973709/48417270-41108d00-e74a-11e8-9172-cba825d027ed.gif
* Full width form sheets
.. image:: https://user-images.githubusercontent.com/973709/48417428-ac5a5f00-e74a-11e8-8839-5bc538c54c1d.png
* Sticky chatter topbar
.. image:: ../static/img/chatter_topbar.gif
* AppMenu waits for action finished to show the view
.. image:: ../static/img/appmenu.gif
* Sticky header & footer in list view
.. image:: ../static/img/listview.gif
* Sticky statusbar in form view
.. image:: ../static/img/formview.gif
* Followers and send button is displayed on mobile. Avatar is hidden.
.. image:: ../static/img/chatter.gif
* When the chatter is configured on the side part, the document viewer fills that
part for side-by-side reading instead of full screen. You can still put it on full
width preview clicking on the new maximize button.
.. image:: ../static/img/document_viewer.gif
* Bigger checkboxes in list view
.. image:: ../static/img/big_checkboxes.gif
* Scrollable dropdowns
.. image:: ../static/img/dropdown_scroll.gif
* To view the full experience in a device, the page must be loaded with the
device screen size. This means that, if you change the size of your browser,
you should reload the web client to get the full experience for that
new size. This is Odoo's own limitation.
* App navigation with keyboard.
* Handle long titles on forms in a better way
* Standard sticky headers seems to not work properly on iOS Safari/Chrome (see #1626).
The following keyboard shortcuts are implemented:
* Navigate app search results - Arrow keys
* Choose app result - ``Enter``
* ``Esc`` to close app drawer
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils 0.15.1: http://docutils.sourceforge.net/" />
<title>Web Responsive</title>
<style type="text/css">
/*
:Author: David Goodger (goodger@python.org)
:Id: $Id: html4css1.css 7952 2016-07-26 18:15:59Z milde $
:Copyright: This stylesheet has been placed in the public domain.
Default cascading style sheet for the HTML output of Docutils.
See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to
customize this style sheet.
*/
/* used to remove borders from tables and images */
.borderless, table.borderless td, table.borderless th {
border: 0 }
table.borderless td, table.borderless th {
/* Override padding for "table.docutils td" with "! important".
The right padding separates the table cells. */
padding: 0 0.5em 0 0 ! important }
.first {
/* Override more specific margin styles with "! important". */
margin-top: 0 ! important }
.last, .with-subtitle {
margin-bottom: 0 ! important }
.hidden {
display: none }
.subscript {
vertical-align: sub;
font-size: smaller }
.superscript {
vertical-align: super;
font-size: smaller }
a.toc-backref {
text-decoration: none ;
color: black }
blockquote.epigraph {
margin: 2em 5em ; }
dl.docutils dd {
margin-bottom: 0.5em }
object[type="image/svg+xml"], object[type="application/x-shockwave-flash"] {
overflow: hidden;
}
/* Uncomment (and remove this text!) to get bold-faced definition list terms
dl.docutils dt {
font-weight: bold }
*/
div.abstract {
margin: 2em 5em }
div.abstract p.topic-title {
font-weight: bold ;
text-align: center }
div.admonition, div.attention, div.caution, div.danger, div.error,
div.hint, div.important, div.note, div.tip, div.warning {
margin: 2em ;
border: medium outset ;
padding: 1em }
div.admonition p.admonition-title, div.hint p.admonition-title,
div.important p.admonition-title, div.note p.admonition-title,
div.tip p.admonition-title {
font-weight: bold ;
font-family: sans-serif }
div.attention p.admonition-title, div.caution p.admonition-title,
div.danger p.admonition-title, div.error p.admonition-title,
div.warning p.admonition-title, .code .error {
color: red ;
font-weight: bold ;
font-family: sans-serif }
/* Uncomment (and remove this text!) to get reduced vertical space in
compound paragraphs.
div.compound .compound-first, div.compound .compound-middle {
margin-bottom: 0.5em }
div.compound .compound-last, div.compound .compound-middle {
margin-top: 0.5em }
*/
div.dedication {
margin: 2em 5em ;
text-align: center ;
font-style: italic }
div.dedication p.topic-title {
font-weight: bold ;
font-style: normal }
div.figure {
margin-left: 2em ;
margin-right: 2em }
div.footer, div.header {
clear: both;
font-size: smaller }
div.line-block {
display: block ;
margin-top: 1em ;
margin-bottom: 1em }
div.line-block div.line-block {
margin-top: 0 ;
margin-bottom: 0 ;
margin-left: 1.5em }
div.sidebar {
margin: 0 0 0.5em 1em ;
border: medium outset ;
padding: 1em ;
background-color: #ffffee ;
width: 40% ;
float: right ;
clear: right }
div.sidebar p.rubric {
font-family: sans-serif ;
font-size: medium }
div.system-messages {
margin: 5em }
div.system-messages h1 {
color: red }
div.system-message {
border: medium outset ;
padding: 1em }
div.system-message p.system-message-title {
color: red ;
font-weight: bold }
div.topic {
margin: 2em }
h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
margin-top: 0.4em }
h1.title {
text-align: center }
h2.subtitle {
text-align: center }
hr.docutils {
width: 75% }
img.align-left, .figure.align-left, object.align-left, table.align-left {
clear: left ;
float: left ;
margin-right: 1em }
img.align-right, .figure.align-right, object.align-right, table.align-right {
clear: right ;
float: right ;
margin-left: 1em }
img.align-center, .figure.align-center, object.align-center {
display: block;
margin-left: auto;
margin-right: auto;
}
table.align-center {
margin-left: auto;
margin-right: auto;
}
.align-left {
text-align: left }
.align-center {
clear: both ;
text-align: center }
.align-right {
text-align: right }
/* reset inner alignment in figures */
div.align-right {
text-align: inherit }
/* div.align-center * { */
/* text-align: left } */
.align-top {
vertical-align: top }
.align-middle {
vertical-align: middle }
.align-bottom {
vertical-align: bottom }
ol.simple, ul.simple {
margin-bottom: 1em }
ol.arabic {
list-style: decimal }
ol.loweralpha {
list-style: lower-alpha }
ol.upperalpha {
list-style: upper-alpha }
ol.lowerroman {
list-style: lower-roman }
ol.upperroman {
list-style: upper-roman }
p.attribution {
text-align: right ;
margin-left: 50% }
p.caption {
font-style: italic }
p.credits {
font-style: italic ;
font-size: smaller }
p.label {
white-space: nowrap }
p.rubric {
font-weight: bold ;
font-size: larger ;
color: maroon ;
text-align: center }
p.sidebar-title {
font-family: sans-serif ;
font-weight: bold ;
font-size: larger }
p.sidebar-subtitle {
font-family: sans-serif ;
font-weight: bold }
p.topic-title {
font-weight: bold }
pre.address {
margin-bottom: 0 ;
margin-top: 0 ;
font: inherit }
pre.literal-block, pre.doctest-block, pre.math, pre.code {
margin-left: 2em ;
margin-right: 2em }
pre.code .ln { color: grey; } /* line numbers */
pre.code, code { background-color: #eeeeee }
pre.code .comment, code .comment { color: #5C6576 }
pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold }
pre.code .literal.string, code .literal.string { color: #0C5404 }
pre.code .name.builtin, code .name.builtin { color: #352B84 }
pre.code .deleted, code .deleted { background-color: #DEB0A1}
pre.code .inserted, code .inserted { background-color: #A3D289}
span.classifier {
font-family: sans-serif ;
font-style: oblique }
span.classifier-delimiter {
font-family: sans-serif ;
font-weight: bold }
span.interpreted {
font-family: sans-serif }
span.option {
white-space: nowrap }
span.pre {
white-space: pre }
span.problematic {
color: red }
span.section-subtitle {
/* font-size relative to parent (h1..h6 element) */
font-size: 80% }
table.citation {
border-left: solid 1px gray;
margin-left: 1px }
table.docinfo {
margin: 2em 4em }
table.docutils {
margin-top: 0.5em ;
margin-bottom: 0.5em }
table.footnote {
border-left: solid 1px black;
margin-left: 1px }
table.docutils td, table.docutils th,
table.docinfo td, table.docinfo th {
padding-left: 0.5em ;
padding-right: 0.5em ;
vertical-align: top }
table.docutils th.field-name, table.docinfo th.docinfo-name {
font-weight: bold ;
text-align: left ;
white-space: nowrap ;
padding-left: 0 }
/* "booktabs" style (no vertical lines) */
table.docutils.booktabs {
border: 0px;
border-top: 2px solid;
border-bottom: 2px solid;
border-collapse: collapse;
}
table.docutils.booktabs * {
border: 0px;
}
table.docutils.booktabs th {
border-bottom: thin solid;
text-align: left;
}
h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
font-size: 100% }
ul.auto-toc {
list-style-type: none }
</style>
</head>
<body>
<div class="document" id="web-responsive">
<h1 class="title">Web Responsive</h1>
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<p><a class="reference external" href="https://odoo-community.org/page/development-status"><img alt="Production/Stable" src="https://img.shields.io/badge/maturity-Production%2FStable-green.png" /></a> <a class="reference external" href="http://www.gnu.org/licenses/lgpl-3.0-standalone.html"><img alt="License: LGPL-3" src="https://img.shields.io/badge/licence-LGPL--3-blue.png" /></a> <a class="reference external" href="https://github.com/OCA/web/tree/14.0/web_responsive"><img alt="OCA/web" src="https://img.shields.io/badge/github-OCA%2Fweb-lightgray.png?logo=github" /></a> <a class="reference external" href="https://translation.odoo-community.org/projects/web-14-0/web-14-0-web_responsive"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external" href="https://runbot.odoo-community.org/runbot/162/14.0"><img alt="Try me on Runbot" src="https://img.shields.io/badge/runbot-Try%20me-875A7B.png" /></a></p>
<p>This module adds responsiveness to web backend.</p>
<p>Features for all devices:</p>
<ul>
<li><p class="first">New navigation with an app drawer</p>
<img alt="https://user-images.githubusercontent.com/973709/48417193-09a1e080-e74a-11e8-8a0c-e73eb689b2fb.gif" src="https://user-images.githubusercontent.com/973709/48417193-09a1e080-e74a-11e8-8a0c-e73eb689b2fb.gif" />
</li>
<li><p class="first">Quick menu search from the app drawer</p>
<img alt="https://user-images.githubusercontent.com/973709/48417213-17576600-e74a-11e8-846a-57691e82636b.gif" src="https://user-images.githubusercontent.com/973709/48417213-17576600-e74a-11e8-846a-57691e82636b.gif" />
</li>
<li><p class="first">Increase the size of the labels in extra large screens</p>
<img alt="https://raw.githubusercontent.com/OCA/web/14.0/web_responsive/static/img/label_size_small.png" src="https://raw.githubusercontent.com/OCA/web/14.0/web_responsive/static/img/label_size_small.png" />
<img alt="https://raw.githubusercontent.com/OCA/web/14.0/web_responsive/static/img/label_size_large.png" src="https://raw.githubusercontent.com/OCA/web/14.0/web_responsive/static/img/label_size_large.png" />
</li>
</ul>
<p>Features for mobile:</p>
<ul>
<li><p class="first">App-specific submenus are shown on full screen when toggling them from the
“hamburger” menu</p>
<img alt="https://user-images.githubusercontent.com/973709/48417297-51286c80-e74a-11e8-9a47-22c810b18c43.gif" src="https://user-images.githubusercontent.com/973709/48417297-51286c80-e74a-11e8-9a47-22c810b18c43.gif" />
</li>
<li><p class="first">View type picker dropdown displays confortably</p>
<img alt="https://user-images.githubusercontent.com/973709/50964322-e3d55580-14c6-11e9-8249-48db9539600f.gif" src="https://user-images.githubusercontent.com/973709/50964322-e3d55580-14c6-11e9-8249-48db9539600f.gif" />
</li>
<li><p class="first">Top app bar is always visible, but the control panel is hidden when
scrolling down, to save some vaulable vertical space</p>
<img alt="https://user-images.githubusercontent.com/973709/50964496-5cd4ad00-14c7-11e9-9261-fd223a329d02.gif" src="https://user-images.githubusercontent.com/973709/50964496-5cd4ad00-14c7-11e9-9261-fd223a329d02.gif" />
</li>
<li><p class="first">Form status bar action and status buttons are collapsed in dropdowns.
Other control panel buttons use icons to save space.</p>
<img alt="https://user-images.githubusercontent.com/973709/50965446-e08f9900-14c9-11e9-92d6-dda472cb6557.gif" src="https://user-images.githubusercontent.com/973709/50965446-e08f9900-14c9-11e9-92d6-dda472cb6557.gif" />
</li>
<li><p class="first">Breadcrumbs navigation is collapsed with a “back arrow” button.</p>
<img alt="https://user-images.githubusercontent.com/973709/50965168-1d0ec500-14c9-11e9-82a0-dfee82ed0861.gif" src="https://user-images.githubusercontent.com/973709/50965168-1d0ec500-14c9-11e9-82a0-dfee82ed0861.gif" />
</li>
<li><p class="first">Search panel is hidden on small screens.</p>
<img alt="https://raw.githubusercontent.com/OCA/web/14.0/web_responsive/static/img/search_panel.gif" src="https://raw.githubusercontent.com/OCA/web/14.0/web_responsive/static/img/search_panel.gif" />
</li>
</ul>
<p>Features for computers:</p>
<ul>
<li><p class="first">Keyboard shortcuts for easier navigation, <strong>using ``Alt + Shift + [key]``</strong>
combination instead of just <tt class="docutils literal">Alt + [key]</tt>.
See <a class="reference external" href="https://github.com/odoo/odoo/issues/30068">https://github.com/odoo/odoo/issues/30068</a> to understand why.</p>
<img alt="https://user-images.githubusercontent.com/973709/48417578-ff341680-e74a-11e8-8881-017709e912bc.png" src="https://user-images.githubusercontent.com/973709/48417578-ff341680-e74a-11e8-8881-017709e912bc.png" />
</li>
<li><p class="first">Autofocus on search menu box when opening the drawer</p>
<img alt="https://user-images.githubusercontent.com/973709/48417213-17576600-e74a-11e8-846a-57691e82636b.gif" src="https://user-images.githubusercontent.com/973709/48417213-17576600-e74a-11e8-846a-57691e82636b.gif" />
</li>
<li><p class="first">Set chatter on the side of the screen, optional per user</p>
<img alt="https://user-images.githubusercontent.com/973709/48417270-41108d00-e74a-11e8-9172-cba825d027ed.gif" src="https://user-images.githubusercontent.com/973709/48417270-41108d00-e74a-11e8-9172-cba825d027ed.gif" />
</li>
<li><p class="first">Full width form sheets</p>
<img alt="https://user-images.githubusercontent.com/973709/48417428-ac5a5f00-e74a-11e8-8839-5bc538c54c1d.png" src="https://user-images.githubusercontent.com/973709/48417428-ac5a5f00-e74a-11e8-8839-5bc538c54c1d.png" />
</li>
<li><p class="first">Sticky chatter topbar</p>
<img alt="https://raw.githubusercontent.com/OCA/web/14.0/web_responsive/static/img/chatter_topbar.gif" src="https://raw.githubusercontent.com/OCA/web/14.0/web_responsive/static/img/chatter_topbar.gif" />
</li>
<li><p class="first">AppMenu waits for action finished to show the view</p>
<img alt="https://raw.githubusercontent.com/OCA/web/14.0/web_responsive/static/img/appmenu.gif" src="https://raw.githubusercontent.com/OCA/web/14.0/web_responsive/static/img/appmenu.gif" />
</li>
<li><p class="first">Sticky header &amp; footer in list view</p>
<img alt="https://raw.githubusercontent.com/OCA/web/14.0/web_responsive/static/img/listview.gif" src="https://raw.githubusercontent.com/OCA/web/14.0/web_responsive/static/img/listview.gif" />
</li>
<li><p class="first">Sticky statusbar in form view</p>
<img alt="https://raw.githubusercontent.com/OCA/web/14.0/web_responsive/static/img/formview.gif" src="https://raw.githubusercontent.com/OCA/web/14.0/web_responsive/static/img/formview.gif" />
</li>
<li><p class="first">Followers and send button is displayed on mobile. Avatar is hidden.</p>
<img alt="https://raw.githubusercontent.com/OCA/web/14.0/web_responsive/static/img/chatter.gif" src="https://raw.githubusercontent.com/OCA/web/14.0/web_responsive/static/img/chatter.gif" />
</li>
<li><p class="first">When the chatter is configured on the side part, the document viewer fills that
part for side-by-side reading instead of full screen. You can still put it on full
width preview clicking on the new maximize button.</p>
<img alt="https://raw.githubusercontent.com/OCA/web/14.0/web_responsive/static/img/document_viewer.gif" src="https://raw.githubusercontent.com/OCA/web/14.0/web_responsive/static/img/document_viewer.gif" />
</li>
<li><p class="first">Bigger checkboxes in list view</p>
<img alt="https://raw.githubusercontent.com/OCA/web/14.0/web_responsive/static/img/big_checkboxes.gif" src="https://raw.githubusercontent.com/OCA/web/14.0/web_responsive/static/img/big_checkboxes.gif" />
</li>
<li><p class="first">Scrollable dropdowns</p>
<img alt="https://raw.githubusercontent.com/OCA/web/14.0/web_responsive/static/img/dropdown_scroll.gif" src="https://raw.githubusercontent.com/OCA/web/14.0/web_responsive/static/img/dropdown_scroll.gif" />
</li>
</ul>
<p><strong>Table of contents</strong></p>
<div class="contents local topic" id="contents">
<ul class="simple">
<li><a class="reference internal" href="#usage" id="id1">Usage</a></li>
<li><a class="reference internal" href="#known-issues-roadmap" id="id2">Known issues / Roadmap</a></li>
<li><a class="reference internal" href="#bug-tracker" id="id3">Bug Tracker</a></li>
<li><a class="reference internal" href="#credits" id="id4">Credits</a><ul>
<li><a class="reference internal" href="#authors" id="id5">Authors</a></li>
<li><a class="reference internal" href="#contributors" id="id6">Contributors</a></li>
<li><a class="reference internal" href="#maintainers" id="id7">Maintainers</a></li>
</ul>
</li>
</ul>
</div>
<div class="section" id="usage">
<h1><a class="toc-backref" href="#id1">Usage</a></h1>
<p>The following keyboard shortcuts are implemented:</p>
<ul class="simple">
<li>Navigate app search results - Arrow keys</li>
<li>Choose app result - <tt class="docutils literal">Enter</tt></li>
<li><tt class="docutils literal">Esc</tt> to close app drawer</li>
</ul>
</div>
<div class="section" id="known-issues-roadmap">
<h1><a class="toc-backref" href="#id2">Known issues / Roadmap</a></h1>
<ul class="simple">
<li>To view the full experience in a device, the page must be loaded with the
device screen size. This means that, if you change the size of your browser,
you should reload the web client to get the full experience for that
new size. This is Odoo’s own limitation.</li>
<li>App navigation with keyboard.</li>
<li>Handle long titles on forms in a better way</li>
<li>Standard sticky headers seems to not work properly on iOS Safari/Chrome (see #1626).</li>
</ul>
</div>
<div class="section" id="bug-tracker">
<h1><a class="toc-backref" href="#id3">Bug Tracker</a></h1>
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/web/issues">GitHub Issues</a>.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us smashing it by providing a detailed and welcomed
<a class="reference external" href="https://github.com/OCA/web/issues/new?body=module:%20web_responsive%0Aversion:%2014.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
<p>Do not contact contributors directly about support or help with technical issues.</p>
</div>
<div class="section" id="credits">
<h1><a class="toc-backref" href="#id4">Credits</a></h1>
<div class="section" id="authors">
<h2><a class="toc-backref" href="#id5">Authors</a></h2>
<ul class="simple">
<li>LasLabs</li>
<li>Tecnativa</li>
</ul>
</div>
<div class="section" id="contributors">
<h2><a class="toc-backref" href="#id6">Contributors</a></h2>
<ul class="simple">
<li>Dave Lasley &lt;<a class="reference external" href="mailto:dave&#64;laslabs.com">dave&#64;laslabs.com</a>&gt;</li>
<li>Jairo Llopis &lt;<a class="reference external" href="mailto:jairo.llopis&#64;tecnativa.com">jairo.llopis&#64;tecnativa.com</a>&gt;</li>
<li>Dennis Sluijk &lt;<a class="reference external" href="mailto:d.sluijk&#64;onestein.nl">d.sluijk&#64;onestein.nl</a>&gt;</li>
<li>Sergio Teruel &lt;<a class="reference external" href="mailto:sergio.teruel&#64;tecnativa.com">sergio.teruel&#64;tecnativa.com</a>&gt;</li>
<li>Alexandre Díaz &lt;<a class="reference external" href="mailto:dev&#64;redneboa.es">dev&#64;redneboa.es</a>&gt;</li>
<li>Mathias Markl &lt;<a class="reference external" href="mailto:mathias.markl&#64;mukit.at">mathias.markl&#64;mukit.at</a>&gt;</li>
<li>Iván Todorovich &lt;<a class="reference external" href="mailto:ivan.todorovich&#64;gmail.com">ivan.todorovich&#64;gmail.com</a>&gt;</li>
<li>Sergey Shebanin &lt;<a class="reference external" href="mailto:sergey&#64;shebanin.ru">sergey&#64;shebanin.ru</a>&gt;</li>
</ul>
</div>
<div class="section" id="maintainers">
<h2><a class="toc-backref" href="#id7">Maintainers</a></h2>
<p>This module is maintained by the OCA.</p>
<a class="reference external image-reference" href="https://odoo-community.org"><img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" /></a>
<p>OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.</p>
<p>Current <a class="reference external" href="https://odoo-community.org/page/maintainer-role">maintainers</a>:</p>
<p><a class="reference external" href="https://github.com/Yajo"><img alt="Yajo" src="https://github.com/Yajo.png?size=40px" /></a> <a class="reference external" href="https://github.com/Tardo"><img alt="Tardo" src="https://github.com/Tardo.png?size=40px" /></a></p>
<p>This module is part of the <a class="reference external" href="https://github.com/OCA/web/tree/14.0/web_responsive">OCA/web</a> project on GitHub.</p>
<p>You are welcome to contribute. To learn how please visit <a class="reference external" href="https://odoo-community.org/page/Contribute">https://odoo-community.org/page/Contribute</a>.</p>
</div>
</div>
</div>
</body>
</html>
<svg xmlns="http://www.w3.org/2000/svg" width="2000" height="1128" viewBox="0 0 2000 1128">
<polygon fill-opacity=".03" points="0 1077.844 392.627 778.443 1504.99 1127.745 0 1127.745"/>
<polygon fill-opacity=".02" points="392.216 778.443 283.294 0 0 0 0 666.504"/>
<polygon fill-opacity=".03" points="1000 0 2000 1009.98 2000 439.94 1749.817 0"/>
</svg>
odoo.define("web_responsive.KanbanRendererMobile", function (require) {
"use strict";
/**
* The purpose of this file is to improve the UX of grouped kanban views in
* mobile. It includes the KanbanRenderer (in mobile only) to only display one
* column full width, and enables the swipe to browse to the other columns.
* Moreover, records in columns are lazy-loaded.
*/
var config = require("web.config");
var core = require("web.core");
var KanbanRenderer = require("web.KanbanRenderer");
var KanbanView = require("web.KanbanView");
var KanbanQuickCreate = require("web.kanban_column_quick_create");
var _t = core._t;
var qweb = core.qweb;
if (!config.device.isMobile) {
return;
}
KanbanQuickCreate.include({
init() {
this._super.apply(this, arguments);
this.isMobile = true;
},
/**
* KanbanRenderer will decide can we close quick create or not
* @private
* @override
*/
_cancel: function () {
this.trigger_up("close_quick_create");
},
/**
* Clear input when showed
* @override
*/
toggleFold: function () {
this._super.apply(this, arguments);
if (!this.folded) {
this.$input.val("");
}
},
});
KanbanView.include({
init() {
this._super.apply(this, arguments);
this.jsLibs.push("/web/static/lib/jquery.touchSwipe/jquery.touchSwipe.js");
},
});
KanbanRenderer.include({
custom_events: _.extend({}, KanbanRenderer.prototype.custom_events || {}, {
quick_create_column_created: "_onColumnAdded",
}),
events: _.extend({}, KanbanRenderer.prototype.events, {
"click .o_kanban_mobile_tab": "_onMobileTabClicked",
"click .o_kanban_mobile_add_column": "_onMobileQuickCreateClicked",
}),
ANIMATE: true, // Allows to disable animations for the tests
/**
* @override
*/
init: function () {
this._super.apply(this, arguments);
this.activeColumnIndex = 0; // Index of the currently displayed column
this._scrollPosition = null;
},
/**
* As this renderer defines its own scrolling area (the column in grouped
* mode), we override this hook to restore the scroll position like it was
* when the renderer has been last detached.
*
* @override
*/
on_attach_callback: function () {
if (
this._scrollPosition &&
this.state.groupedBy.length &&
this.widgets.length
) {
var $column = this.widgets[this.activeColumnIndex].$el;
$column.scrollLeft(this._scrollPosition.left);
$column.scrollTop(this._scrollPosition.top);
}
this._computeTabPosition();
this._super.apply(this, arguments);
},
/**
* As this renderer defines its own scrolling area (the column in grouped
* mode), we override this hook to store the scroll position, so that we can
* restore it if the renderer is re-attached to the DOM later.
*
* @override
*/
on_detach_callback: function () {
if (this.state.groupedBy.length && this.widgets.length) {
var $column = this.widgets[this.activeColumnIndex].$el;
this._scrollPosition = {
left: $column.scrollLeft(),
top: $column.scrollTop(),
};
} else {
this._scrollPosition = null;
}
this._super.apply(this, arguments);
},
// --------------------------------------------------------------------------
// Public
// --------------------------------------------------------------------------
/**
* Displays the quick create record in the active column
* override to open quick create record in current active column
*
* @override
* @returns {Promise}
*/
addQuickCreate: function () {
if (this._canCreateColumn() && !this.quickCreate.folded) {
this._onMobileQuickCreateClicked();
}
return this.widgets[this.activeColumnIndex].addQuickCreate();
},
/**
* Overrides to restore the left property and the scrollTop on the updated
* column, and to enable the swipe handlers
*
* @override
*/
updateColumn: function (localID) {
var index = _.findIndex(this.widgets, {db_id: localID});
var $column = this.widgets[index].$el;
var scrollTop = $column.scrollTop();
return (
this._super
.apply(this, arguments)
.then(() => this._layoutUpdate(false))
// Required when clicking on 'Load More'
.then(() => $column.scrollTop(scrollTop))
.then(() => this._enableSwipe())
);
},
// --------------------------------------------------------------------------
// Private
// --------------------------------------------------------------------------
/**
* Check if we use the quick create on mobile
* @returns {Boolean}
* @private
*/
_canCreateColumn: function () {
return this.quickCreateEnabled && this.quickCreate && this.widgets.length;
},
/**
* Update the columns positions
*
* @private
* @param {Boolean} [animate=false] set to true to animate
*/
_computeColumnPosition: function (animate) {
if (this.widgets.length) {
// Check rtl to compute correct css value
const rtl = _t.database.parameters.direction === "rtl";
// Display all o_kanban_group
this.$(".o_kanban_group").show();
const $columnAfter = this._toNode(
this.widgets.filter(
(widget, index) => index > this.activeColumnIndex
)
);
const promiseAfter = this._updateColumnCss(
$columnAfter,
rtl ? {right: "100%"} : {left: "100%"},
animate
);
const $columnBefore = this._toNode(
this.widgets.filter(
(widget, index) => index < this.activeColumnIndex
)
);
const promiseBefore = this._updateColumnCss(
$columnBefore,
rtl ? {right: "-100%"} : {left: "-100%"},
animate
);
const $columnCurrent = this._toNode(
this.widgets.filter(
(widget, index) => index === this.activeColumnIndex
)
);
const promiseCurrent = this._updateColumnCss(
$columnCurrent,
rtl ? {right: "0%"} : {left: "0%"},
animate
);
promiseAfter
.then(promiseBefore)
.then(promiseCurrent)
.then(() => {
$columnAfter.hide();
$columnBefore.hide();
});
}
},
/**
* Define the o_current class to the current selected kanban (column & tab)
*
* @private
*/
_computeCurrentColumn: function () {
if (this.widgets.length) {
var column = this.widgets[this.activeColumnIndex];
if (!column) {
return;
}
var columnID = column.id || column.db_id;
this.$(
".o_kanban_mobile_tab.o_current, .o_kanban_group.o_current"
).removeClass("o_current");
this.$(
'.o_kanban_group[data-id="' +
columnID +
'"], ' +
'.o_kanban_mobile_tab[data-id="' +
columnID +
'"]'
).addClass("o_current");
}
},
/**
* Update the tabs positions
*
* @private
*/
_computeTabPosition: function () {
this._computeTabJustification();
this._computeTabScrollPosition();
},
/**
* Update the tabs positions
*
* @private
*/
_computeTabScrollPosition: function () {
if (this.widgets.length) {
var lastItemIndex = this.widgets.length - 1;
var moveToIndex = this.activeColumnIndex;
var scrollToLeft = 0;
for (var i = 0; i < moveToIndex; i++) {
var columnWidth = this._getTabWidth(this.widgets[i]);
// Apply
if (moveToIndex !== lastItemIndex && i === moveToIndex - 1) {
var partialWidth = 0.75;
scrollToLeft += columnWidth * partialWidth;
} else {
scrollToLeft += columnWidth;
}
}
// Apply the scroll x on the tabs
// XXX in case of RTL, should we use scrollRight?
this.$(".o_kanban_mobile_tabs").scrollLeft(scrollToLeft);
}
},
/**
* Compute the justify content of the kanban tab headers
*
* @private
*/
_computeTabJustification: function () {
if (this.widgets.length) {
var self = this;
// Use to compute the sum of the width of all tab
var widthChilds = this.widgets.reduce(function (total, column) {
return total + self._getTabWidth(column);
}, 0);
// Apply a space around between child if the parent length is higher then the sum of the child width
var $tabs = this.$(".o_kanban_mobile_tabs");
$tabs.toggleClass(
"justify-content-between",
$tabs.outerWidth() >= widthChilds
);
}
},
/**
* Enables swipe event on the current column
*
* @private
*/
_enableSwipe: function () {
var self = this;
var step = _t.database.parameters.direction === "rtl" ? -1 : 1;
this.$el.swipe({
excludedElements: ".o_kanban_mobile_tabs",
swipeLeft: function () {
var moveToIndex = self.activeColumnIndex + step;
if (moveToIndex < self.widgets.length) {
self._moveToGroup(moveToIndex, self.ANIMATE);
}
},
swipeRight: function () {
var moveToIndex = self.activeColumnIndex - step;
if (moveToIndex > -1) {
self._moveToGroup(moveToIndex, self.ANIMATE);
}
},
});
},
/**
* Retrieve the outerWidth of a given widget column
*
* @param {KanbanColumn} column
* @returns {integer} outerWidth of the found column
* @private
*/
_getTabWidth: function (column) {
var columnID = column.id || column.db_id;
return this.$(
'.o_kanban_mobile_tab[data-id="' + columnID + '"]'
).outerWidth();
},
/**
* Update the kanban layout
*
* @private
* @param {Boolean} [animate=false] set to true to animate
*/
_layoutUpdate: function (animate) {
this._computeCurrentColumn();
this._computeTabPosition();
this._computeColumnPosition(animate);
this._enableSwipe();
},
/**
* Moves to the given kanban column
*
* @private
* @param {integer} moveToIndex index of the column to move to
* @param {Boolean} [animate=false] set to true to animate
* @returns {Promise} resolved when the new current group has been loaded
* and displayed
*/
_moveToGroup: function (moveToIndex, animate) {
if (this.widgets.length === 0) {
return Promise.resolve();
}
var self = this;
if (moveToIndex >= 0 && moveToIndex < this.widgets.length) {
this.activeColumnIndex = moveToIndex;
}
var column = this.widgets[this.activeColumnIndex];
this._enableSwipe();
if (!column.data.isOpen) {
this.trigger_up("column_toggle_fold", {
db_id: column.db_id,
onSuccess: () => self._layoutUpdate(animate),
});
} else {
this._layoutUpdate(animate);
}
return Promise.resolve();
},
/**
* @override
* @private
*/
_renderExampleBackground: function () {
// Override to avoid display of example background
},
/**
* @override
* @private
*/
_renderGrouped: function (fragment) {
var self = this;
var newFragment = document.createDocumentFragment();
this._super.apply(this, [newFragment]);
this.defs.push(
Promise.all(this.defs).then(function () {
var data = [];
_.each(self.state.data, function (group) {
if (!group.value) {
group = _.extend({}, group, {value: _t("Undefined")});
data.unshift(group);
} else {
data.push(group);
}
});
var kanbanColumnContainer = document.createElement("div");
kanbanColumnContainer.classList.add("o_kanban_columns_content");
kanbanColumnContainer.appendChild(newFragment);
fragment.appendChild(kanbanColumnContainer);
$(
qweb.render("KanbanView.MobileTabs", {
data: data,
quickCreateEnabled: self._canCreateColumn(),
})
).prependTo(fragment);
})
);
},
/**
* @override
* @private
*/
_renderView: function () {
var self = this;
return this._super.apply(this, arguments).then(function () {
if (self.state.groupedBy.length) {
// Force first column for kanban view, because the groupedBy can be changed
return self._moveToGroup(0);
}
if (self._canCreateColumn()) {
self._onMobileQuickCreateClicked();
}
return Promise.resolve();
});
},
/**
* Retrieve the Jquery node (.o_kanban_group) for a list of a given widgets
*
* @private
* @param widgets
* @returns {jQuery} the matching .o_kanban_group widgets
*/
_toNode: function (widgets) {
const selectorCss = widgets
.map(
(widget) =>
'.o_kanban_group[data-id="' + (widget.id || widget.db_id) + '"]'
)
.join(", ");
return this.$(selectorCss);
},
/**
* Update the given column to the updated positions
*
* @private
* @param $column The jquery column
* @param cssProperties Use to update column
* @param {Boolean} [animate=false] set to true to animate
* @returns {Promise}
*/
_updateColumnCss: function ($column, cssProperties, animate) {
if (animate) {
return new Promise((resolve) =>
$column.animate(cssProperties, "fast", resolve)
);
}
$column.css(cssProperties);
return Promise.resolve();
},
// --------------------------------------------------------------------------
// Handlers
// --------------------------------------------------------------------------
/**
* @private
*/
_onColumnAdded: function () {
this._computeTabPosition();
if (this._canCreateColumn() && !this.quickCreate.folded) {
this.quickCreate.toggleFold();
}
},
/**
* @private
*/
_onMobileQuickCreateClicked: function (event) {
if (event) {
event.stopPropagation();
}
this.quickCreate.toggleFold();
this.$(".o_kanban_group").toggle(this.quickCreate.folded);
},
/**
* @private
* @param {MouseEvent} event
*/
_onMobileTabClicked: function (event) {
if (this._canCreateColumn() && !this.quickCreate.folded) {
this.quickCreate.toggleFold();
}
this._moveToGroup($(event.currentTarget).index(), true);
},
/**
* @private
* @override
*/
_onCloseQuickCreate: function () {
if (this.widgets.length && !this.quickCreate.folded) {
this.$(".o_kanban_group").toggle(true);
this.quickCreate.toggleFold();
}
},
});
});
/* Copyright 2018 Tecnativa - Jairo Llopis
* Copyright 2018 Tecnativa - Sergey Shebanin
* License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */
odoo.define("web_responsive", function (require) {
"use strict";
const ActionManager = require("web.ActionManager");
const AbstractWebClient = require("web.AbstractWebClient");
const AppsMenu = require("web.AppsMenu");
const BasicController = require("web.BasicController");
const config = require("web.config");
const core = require("web.core");
const FormRenderer = require("web.FormRenderer");
const Menu = require("web.Menu");
const RelationalFields = require("web.relational_fields");
const ListRenderer = require("web.ListRenderer");
const CalendarRenderer = require("web.CalendarRenderer");
const patchMixin = require("web.patchMixin");
const AttachmentViewer = require("mail/static/src/components/attachment_viewer/attachment_viewer.js");
const PatchableAttachmentViewer = patchMixin(AttachmentViewer);
const ControlPanel = require("web.ControlPanel");
const SearchPanel = require("web/static/src/js/views/search_panel.js");
/* global owl */
const {QWeb, Context} = owl;
const {useState, useContext} = owl.hooks;
/* Hide AppDrawer in desktop and mobile modes.
* To avoid delays in pages with a lot of DOM nodes we make
* sub-groups' with 'querySelector' to improve the performance.
*/
function closeAppDrawer() {
_.defer(function () {
// Need close AppDrawer?
var menu_apps_dropdown = document.querySelector(".o_menu_apps .dropdown");
$(menu_apps_dropdown)
.has(".dropdown-menu.show")
.find("> a")
.dropdown("toggle");
// Need close Sections Menu?
// TODO: Change to 'hide' in modern Bootstrap >4.1
var menu_sections = document.querySelector(
".o_menu_sections li.show .dropdown-toggle"
);
$(menu_sections).dropdown("toggle");
// Need close Mobile?
var menu_sections_mobile = document.querySelector(".o_menu_sections.show");
$(menu_sections_mobile).collapse("hide");
});
}
/**
* Reduce menu data to a searchable format understandable by fuzzy.js
*
* `AppsMenu.init()` gets `menuData` in a format similar to this (only
* relevant data is shown):
*
* ```js
* {
* [...],
* children: [
* // This is a menu entry:
* {
* action: "ir.actions.client,94", // Or `false`
* children: [... similar to above "children" key],
* name: "Actions",
* parent_id: [146, "Settings/Technical/Actions"], // Or `false`
* },
* ...
* ]
* }
* ```
*
* This format is very hard to process to search matches, and it would
* slow down the search algorithm, so we reduce it with this method to be
* able to later implement a simpler search.
*
* @param {Object} memo
* Reference to current result object, passed on recursive calls.
*
* @param {Object} menu
* A menu entry, as described above.
*
* @returns {Object}
* Reduced object, without entries that have no action, and with a
* format like this:
*
* ```js
* {
* "Discuss": {Menu entry Object},
* "Settings": {Menu entry Object},
* "Settings/Technical/Actions/Actions": {Menu entry Object},
* ...
* }
* ```
*/
function findNames(memo, menu) {
if (menu.action) {
var key = menu.parent_id ? menu.parent_id[1] + "/" : "";
memo[key + menu.name] = menu;
}
if (menu.children.length) {
_.reduce(menu.children, findNames, memo);
}
return memo;
}
AppsMenu.include({
events: _.extend(
{
"keydown .search-input input": "_searchResultsNavigate",
"input .search-input input": "_searchMenusSchedule",
"click .o-menu-search-result": "_searchResultChosen",
"shown.bs.dropdown": "_searchFocus",
"hidden.bs.dropdown": "_searchReset",
"hide.bs.dropdown": "_hideAppsMenu",
},
AppsMenu.prototype.events
),
/**
* Rescue some menu data stripped out in original method.
*
* @override
*/
init: function (parent, menuData) {
this._super.apply(this, arguments);
// Keep base64 icon for main menus
for (const n in this._apps) {
this._apps[n].web_icon_data = menuData.children[n].web_icon_data;
}
// Store menu data in a format searchable by fuzzy.js
this._searchableMenus = _.reduce(menuData.children, findNames, {});
// Search only after timeout, for fast typers
this._search_def = false;
},
/**
* @override
*/
start: function () {
this.$search_container = this.$(".search-container");
this.$search_input = this.$(".search-input input");
this.$search_results = this.$(".search-results");
return this._super.apply(this, arguments);
},
/**
* Prevent the menu from being opened twice
*
* @override
*/
_onAppsMenuItemClicked: function (ev) {
this._super.apply(this, arguments);
ev.preventDefault();
ev.stopPropagation();
},
/**
* Get all info for a given menu.
*
* @param {String} key
* Full path to requested menu.
*
* @returns {Object}
* Menu definition, plus extra needed keys.
*/
_menuInfo: function (key) {
const original = this._searchableMenus[key];
return _.extend(
{
action_id: parseInt(original.action.split(",")[1], 10),
},
original
);
},
/**
* Autofocus on search field on big screens.
*/
_searchFocus: function () {
if (!config.device.isMobile) {
// This timeout is necessary since the menu has a 100ms fading animation
setTimeout(() => this.$search_input.focus(), 100);
}
},
/**
* Reset search input and results
*/
_searchReset: function () {
this.$search_container.removeClass("has-results");
this.$search_results.empty();
this.$search_input.val("");
},
/**
* Schedule a search on current menu items.
*/
_searchMenusSchedule: function () {
this._search_def = new Promise((resolve) => {
setTimeout(resolve, 50);
});
this._search_def.then(this._searchMenus.bind(this));
},
/**
* Search among available menu items, and render that search.
*/
_searchMenus: function () {
const query = this.$search_input.val();
if (query === "") {
this.$search_container.removeClass("has-results");
this.$search_results.empty();
return;
}
var results = fuzzy.filter(query, _.keys(this._searchableMenus), {
pre: "<b>",
post: "</b>",
});
this.$search_container.toggleClass("has-results", Boolean(results.length));
this.$search_results.html(
core.qweb.render("web_responsive.MenuSearchResults", {
results: results,
widget: this,
})
);
},
/**
* Use chooses a search result, so we navigate to that menu
*
* @param {jQuery.Event} event
*/
_searchResultChosen: function (event) {
event.preventDefault();
event.stopPropagation();
const $result = $(event.currentTarget),
text = $result.text().trim(),
data = $result.data(),
suffix = ~text.indexOf("/") ? "/" : "";
// Load the menu view
this.trigger_up("menu_clicked", {
action_id: data.actionId,
id: data.menuId,
previous_menu_id: data.parentId,
});
// Find app that owns the chosen menu
const app = _.find(this._apps, function (_app) {
return text.indexOf(_app.name + suffix) === 0;
});
// Update navbar menus
core.bus.trigger("change_menu_section", app.menuID);
},
/**
* Navigate among search results
*
* @param {jQuery.Event} event
*/
_searchResultsNavigate: function (event) {
// Find current results and active element (1st by default)
const all = this.$search_results.find(".o-menu-search-result"),
pre_focused = all.filter(".active") || $(all[0]);
let offset = all.index(pre_focused),
key = event.key;
// Keyboard navigation only supports search results
if (!all.length) {
return;
}
// Transform tab presses in arrow presses
if (key === "Tab") {
event.preventDefault();
key = event.shiftKey ? "ArrowUp" : "ArrowDown";
}
switch (key) {
// Pressing enter is the same as clicking on the active element
case "Enter":
pre_focused.click();
break;
// Navigate up or down
case "ArrowUp":
offset--;
break;
case "ArrowDown":
offset++;
break;
default:
// Other keys are useless in this event
return;
}
// Allow looping on results
if (offset < 0) {
offset = all.length + offset;
} else if (offset >= all.length) {
offset -= all.length;
}
// Switch active element
const new_focused = $(all[offset]);
pre_focused.removeClass("active");
new_focused.addClass("active");
this.$search_results.scrollTo(new_focused, {
offset: {
top: this.$search_results.height() * -0.5,
},
});
},
/*
* Control if AppDrawer can be closed
*/
_hideAppsMenu: function () {
return !this.$("input").is(":focus");
},
});
BasicController.include({
/**
* Close the AppDrawer if the data set is dirty and a discard dialog
* is opened
*
* @override
*/
canBeDiscarded: function (recordID) {
if (this.model.isDirty(recordID || this.handle)) {
closeAppDrawer();
}
return this._super.apply(this, arguments);
},
});
Menu.include({
events: _.extend(
{
// Clicking a hamburger menu item should close the hamburger
"click .o_menu_sections [role=menuitem]": "_onClickMenuItem",
// Opening any dropdown in the navbar should hide the hamburger
"show.bs.dropdown .o_menu_systray, .o_menu_apps": "_hideMobileSubmenus",
},
Menu.prototype.events
),
start: function () {
this.$menu_toggle = this.$(".o-menu-toggle");
return this._super.apply(this, arguments);
},
/**
* Hide menus for current app if you're in mobile
*/
_hideMobileSubmenus: function () {
if (
config.device.isMobile &&
this.$menu_toggle.is(":visible") &&
this.$section_placeholder.is(":visible")
) {
this.$section_placeholder.collapse("hide");
}
},
/**
* Prevent hide the menu (should be closed when action is loaded)
*
* @param {ClickEvent} ev
*/
_onClickMenuItem: function (ev) {
ev.stopPropagation();
},
/**
* No menu brand in mobiles
*
* @override
*/
_updateMenuBrand: function () {
if (!config.device.isMobile) {
return this._super.apply(this, arguments);
}
},
});
RelationalFields.FieldStatus.include({
/**
* Fold all on mobiles.
*
* @override
*/
_setState: function () {
this._super.apply(this, arguments);
if (config.device.isMobile) {
_.map(this.status_information, (value) => {
value.fold = true;
});
}
},
});
// Sticky Column Selector
ListRenderer.include({
_renderView: function () {
const self = this;
return this._super.apply(this, arguments).then(() => {
const $col_selector = self.$el.find(
".o_optional_columns_dropdown_toggle"
);
if ($col_selector.length !== 0) {
const $th = self.$el.find("thead>tr:first>th:last");
$col_selector.appendTo($th);
}
});
},
_onToggleOptionalColumnDropdown: function (ev) {
// FIXME: For some strange reason the 'stopPropagation' call
// in the main method don't work. Invoking here the same method
// does the expected behavior... O_O!
// This prevents the action of sorting the column from being
// launched.
ev.stopPropagation();
this._super.apply(this, arguments);
},
});
// Responsive view "action" buttons
FormRenderer.include({
/**
* In mobiles, put all statusbar buttons in a dropdown.
*
* @override
*/
_renderHeaderButtons: function () {
const $buttons = this._super.apply(this, arguments);
if (
!config.device.isMobile ||
$buttons.children("button:not(.o_invisible_modifier)").length <= 2
) {
return $buttons;
}
// $buttons must be appended by JS because all events are bound
const $dropdown = $(
core.qweb.render("web_responsive.MenuStatusbarButtons")
);
$buttons.addClass("dropdown-menu").appendTo($dropdown);
return $dropdown;
},
});
CalendarRenderer.include({
_getFullCalendarOptions: function () {
var options = this._super.apply(this, arguments);
if (config.device.isMobile) {
options.views.dayGridMonth.columnHeaderFormat = "ddd";
}
return options;
},
});
// Hide AppDrawer or Menu when the action has been completed
ActionManager.include({
/**
* @override
*/
_appendController: function () {
this._super.apply(this, arguments);
closeAppDrawer();
},
});
/**
* Use ALT+SHIFT instead of ALT as hotkey triggerer.
*
* HACK https://github.com/odoo/odoo/issues/30068 - See it to know why.
*
* Cannot patch in `KeyboardNavigationMixin` directly because it's a mixin,
* not a `Class`, and altering a mixin's `prototype` doesn't alter it where
* it has already been used.
*
* Instead, we provide an additional mixin to be used wherever you need to
* enable this behavior.
*/
var KeyboardNavigationShiftAltMixin = {
/**
* Alter the key event to require pressing Shift.
*
* This will produce a mocked event object where it will seem that
* `Alt` is not pressed if `Shift` is not pressed.
*
* The reason for this is that original upstream code, found in
* `KeyboardNavigationMixin` is very hardcoded against the `Alt` key,
* so it is more maintainable to mock its input than to rewrite it
* completely.
*
* @param {keyEvent} keyEvent
* Original event object
*
* @returns {keyEvent}
* Altered event object
*/
_shiftPressed: function (keyEvent) {
const alt = keyEvent.altKey || keyEvent.key === "Alt",
newEvent = _.extend({}, keyEvent),
shift = keyEvent.shiftKey || keyEvent.key === "Shift";
// Mock event to make it seem like Alt is not pressed
if (alt && !shift) {
newEvent.altKey = false;
if (newEvent.key === "Alt") {
newEvent.key = "Shift";
}
}
return newEvent;
},
_onKeyDown: function (keyDownEvent) {
return this._super(this._shiftPressed(keyDownEvent));
},
_onKeyUp: function (keyUpEvent) {
return this._super(this._shiftPressed(keyUpEvent));
},
};
// Include the SHIFT+ALT mixin wherever
// `KeyboardNavigationMixin` is used upstream
AbstractWebClient.include(KeyboardNavigationShiftAltMixin);
// TODO: use default odoo device context when it will be realized
const deviceContext = new Context({
isMobile: config.device.isMobile,
size_class: config.device.size_class,
SIZES: config.device.SIZES,
});
window.addEventListener(
"resize",
owl.utils.debounce(() => {
const state = deviceContext.state;
if (state.isMobile !== config.device.isMobile) {
state.isMobile = !state.isMobile;
}
if (state.size_class !== config.device.size_class) {
state.size_class = config.device.size_class;
}
}, 15)
);
// Patch attachment viewer to add min/max buttons capability
PatchableAttachmentViewer.patch("web_responsive.AttachmentViewer", (T) => {
class AttachmentViewerPatchResponsive extends T {
constructor() {
super(...arguments);
this.state = useState({
maximized: false,
});
}
// Disable auto-close to allow to use form in edit mode.
isCloseable() {
return false;
}
}
return AttachmentViewerPatchResponsive;
});
QWeb.components.AttachmentViewer = PatchableAttachmentViewer;
// Patch control panel to add states for mobile quick search
ControlPanel.patch("web_responsive.ControlPanelMobile", (T) => {
class ControlPanelPatchResponsive extends T {
constructor() {
super(...arguments);
this.state = useState({
mobileSearchMode: "",
});
this.device = useContext(deviceContext);
}
}
return ControlPanelPatchResponsive;
});
// Patch search panel to add functionality for mobile view
SearchPanel.patch("web_responsive.SearchPanelMobile", (T) => {
class SearchPanelPatchResponsive extends T {
constructor() {
super(...arguments);
this.state.mobileSearch = false;
this.device = useContext(deviceContext);
}
getActiveSummary() {
const selection = [];
for (const filter of this.model.get("sections")) {
let filterValues = [];
if (filter.type === "category") {
if (filter.activeValueId) {
const parentIds = this._getAncestorValueIds(
filter,
filter.activeValueId
);
filterValues = [...parentIds, filter.activeValueId].map(
(valueId) => filter.values.get(valueId).display_name
);
}
} else {
let values = [];
if (filter.groups) {
values = Array.from(
filter.groups.values(),
(g) => g.values
).flat();
}
if (filter.values) {
values = [...filter.values.values()];
}
filterValues = values
.filter((v) => v.checked)
.map((v) => v.display_name);
}
if (filterValues.length) {
selection.push({
values: filterValues,
icon: filter.icon,
color: filter.color,
type: filter.type,
});
}
}
return selection;
}
}
return SearchPanelPatchResponsive;
});
return {
deviceContext: deviceContext,
};
});
@include media-breakpoint-down(sm) {
.o_kanban_view.o_kanban_grouped {
display: block;
position: relative;
overflow-x: hidden;
&.o_renderer_with_searchpanel {
width: 100%;
}
.o_kanban_mobile_tabs_container {
position: sticky;
display: flex;
justify-content: space-between;
width: 100%;
top: 0;
z-index: 1;
background-color: #5e5e5e;
.o_kanban_mobile_add_column {
height: $o-kanban-mobile-tabs-height;
padding: 10px;
border-left: grey 1px solid;
color: white;
font-size: 14px;
}
.o_kanban_mobile_tabs {
position: relative;
display: flex;
width: 100%;
height: $o-kanban-mobile-tabs-height;
overflow-x: auto;
.o_kanban_mobile_tab {
height: $o-kanban-mobile-tabs-height;
padding: 10px 20px;
font-size: 14px;
color: white;
&.o_current {
font-weight: bold;
border-bottom: 3px solid $o-brand-primary;
}
.o_column_title {
white-space: nowrap;
text-transform: uppercase;
}
}
}
}
.o_kanban_columns_content {
position: relative;
}
// [class] to get same specificity as elsewhere (kanban_view.less)
&[class] .o_kanban_group:not(.o_column_folded) {
@include o-position-absolute(
$top: $o-kanban-mobile-tabs-height,
$left: 0,
$bottom: 0
);
width: 100%;
padding: 0;
margin-left: 0; // override the margin-left: -1px of the desktop mode
border: none;
&.o_current {
position: inherit;
top: 0;
&.o_kanban_no_records {
// set a default height for clarity when embedded in another view
min-height: $o-kanban-mobile-empty-height;
}
}
.o_kanban_header {
display: none;
}
.o_kanban_record,
.o_kanban_quick_create {
border: none;
border-bottom: 1px solid lightgray;
padding: 10px 16px;
margin: 0;
}
}
}
.o_kanban_view .o_column_quick_create {
.o_quick_create_folded {
display: none !important;
}
.o_quick_create_unfolded {
width: 100%;
}
}
}
.o_web_client {
.o_mobile_search {
position: fixed;
top: 0;
left: 0;
bottom: 0;
padding: 0;
width: 100%;
background-color: white;
z-index: $zindex-modal;
overflow: auto;
.o_mobile_search_header {
height: 46px;
margin-bottom: 10px;
width: 100%;
background-color: $o-brand-odoo;
color: white;
span:active {
background-color: darken($o-brand-primary, 10%);
}
span {
cursor: pointer;
}
}
.o_searchview_input_container {
display: flex;
padding: 15px 20px 0 20px;
position: relative;
.o_searchview_input {
width: 100%;
margin-bottom: 15px;
border-bottom: 1px solid $o-brand-secondary;
}
.o_searchview_facet {
border-radius: 10px;
display: inline-flex;
order: 1;
.o_searchview_facet_label {
border-radius: 2em 0em 0em 2em;
}
}
.o_searchview_autocomplete {
top: 100%;
> li {
margin: 5px 0px;
}
}
}
.o_mobile_search_filter {
padding-bottom: 15%;
.o_dropdown {
width: 100%;
margin: 15px 5px 0px 5px;
border: solid 1px darken(gray("200"), 20%);
}
.o_dropdown_toggler_btn {
width: 100%;
text-align: left;
&:after {
display: none;
}
}
// We disable the backdrop in this case because it prevents any
// interaction outside of a dropdown while it is open.
.dropdown-backdrop {
z-index: -1;
}
.dropdown-menu {
// Here we use !important because of popper js adding custom style
// to element so to override it use !important
position: relative !important;
width: 100% !important;
transform: translate3d(0, 0, 0) !important;
box-shadow: none;
border: none;
color: gray("600");
.divider {
margin: 0px;
}
> li > a {
padding: 10px 26px;
}
}
}
.o_mobile_search_show_result {
padding: 10px;
font-size: 15px;
}
}
}
// Search panel
@include media-breakpoint-down(sm) {
.o_controller_with_searchpanel {
display: block;
.o_search_panel {
height: auto;
padding: 8px;
border-left: 1px solid $gray-300;
section {
padding: 0px 16px;
}
}
.o_search_panel_summary {
cursor: pointer;
}
}
}
/* Copyright 2018 Tecnativa - Jairo Llopis
* License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */
$chatter_zone_width: 35%;
@mixin full-screen-dropdown {
border: none;
box-shadow: none;
display: flex;
flex-direction: column;
height: calc(100vh - #{$o-navbar-height});
position: fixed;
margin: 0;
width: 100vw;
z-index: 100;
// Inline style will override our `top`, so we need !important here
top: $o-navbar-height !important;
transform: none !important;
}
// Support for long titles
@include media-breakpoint-up(md) {
.o_form_view .oe_button_box + .oe_title,
.o_form_view .oe_button_box + .oe_avatar + .oe_title {
/* Button-box has a hardcoded width of 132px per button and have three columns */
width: calc(100% - 450px);
}
}
// Main navbar (with apps menu, user menu, debug menu...)
@include media-breakpoint-down(sm) {
.o_main_navbar {
// This allows to have a sane layout for mobiles
display: flex;
// Remove clutter to only have small icons that fit in a small screen
> .dropdown {
display: flex;
.navbar-toggler {
color: gray("white");
}
.o_menu_sections,
.o_menu_systray {
padding: 0;
}
}
// Whitespace before systray icons
.o_menu_systray {
margin-left: auto;
}
// Hide big things
.o_menu_brand,
.o_menu_sections,
.oe_topbar_name {
display: none;
}
// Fix toggler button padding
.o-menu-toggle {
cursor: pointer;
padding: 0 $o-horizontal-padding;
}
// Custom fullscreen layout when showing submenus
.o_menu_sections.show {
@include full-screen-dropdown();
background-color: $dropdown-bg;
overflow: auto;
.show {
display: flex;
flex-direction: column;
.dropdown-menu {
margin-left: 1rem;
min-width: auto;
width: calc(100vw - 2rem);
}
}
> li,
.o_menu_entry_lvl_1,
.o_menu_header_lvl_1 {
// Homogeneous background color
background-color: $dropdown-bg;
color: $dropdown-link-color;
&:hover {
background-color: $dropdown-link-hover-bg;
color: $dropdown-link-hover-color;
}
// Disable the .o-no-caret class effect, to display the caret
&.o-no-caret::after {
content: "";
}
// Fix a strange glitch leaving headers invisible
.dropdown-header {
color: $dropdown-header-color;
}
}
}
// Custom fullscreen layout for systray items
.o_mail_systray_dropdown.show {
@include full-screen-dropdown();
// Fix stretchy images
.o_mail_preview_image {
align-items: center;
display: flex;
flex-direction: row;
img {
display: block;
height: auto;
}
}
}
// Higher height for dropdown items, for those with sausage fingers
.dropdown-menu .dropdown-item {
padding: {
bottom: 0.5rem;
top: 0.5rem;
}
}
}
}
.o_main_navbar {
color: color-yiq($o-brand-odoo);
> ul > li > a,
> ul > li > label {
color: color-yiq($o-brand-odoo);
}
.dropdown-menu.show {
max-height: calc(100vh - #{$o-navbar-height});
}
}
// Iconized full screen apps menu
.o_menu_apps {
user-select: none;
a.full {
width: $o-navbar-height;
text-align: center;
}
.dropdown-menu.show {
opacity: 1;
visibility: visible;
}
.dropdown-menu {
@include full-screen-dropdown();
opacity: 0;
visibility: hidden;
transition: visibility 100ms ease, opacity 100ms ease;
background: url("../img/home-menu-bg-overlay.svg"),
linear-gradient(
to bottom,
$o-brand-odoo,
desaturate(lighten($o-brand-odoo, 20%), 15)
);
background-size: cover;
border-radius: 0;
// Display apps in a grid
align-content: flex-start;
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: flex-start;
@include media-breakpoint-up(lg) {
padding: {
left: calc((100vw - 850px) / 2);
right: calc((100vw - 850px) / 2);
}
}
.o_app {
align-items: center;
display: flex;
padding: 10px 0;
border-radius: 4px;
flex-direction: column;
justify-content: flex-start;
background: none;
transition: 300ms ease;
transition-property: background-color;
white-space: normal;
text-align: center;
img {
box-shadow: none;
transition: 300ms ease;
transition-property: box-shadow, transform;
}
&:focus {
background-color: rgba(gray("white"), 0.05);
}
// Size depends on screen
width: 33.33333333%;
@include media-breakpoint-up(sm) {
width: 25%;
}
@include media-breakpoint-up(md) {
width: 16.6666666%;
}
}
.o_app:hover img {
transform: translateY(-3px);
box-shadow: 0 9px 12px -4px rgba(gray("black"), 0.3);
}
// Hide app icons when searching
.has-results ~ .o_app {
display: none;
}
.o-app-icon {
height: auto;
max-width: 6rem;
}
.o-app-name {
color: gray("white");
margin-top: 4px;
font-size: 1.25rem;
text-shadow: 1px 1px 1px rgba(gray("black"), 0.4);
}
// Search input for menus
.form-row {
width: 100%;
}
.o-menu-search-result {
align-items: center;
background-position: left;
background-repeat: no-repeat;
background-size: contain;
cursor: pointer;
padding-left: 3rem;
white-space: normal;
}
.search-container {
padding-top: 1rem;
padding-bottom: 1.5rem;
.search-input {
margin-bottom: 0 !important;
padding: 0;
.input-group {
box-shadow: inset 0 1px 0 rgba(gray("white"), 0.1),
0 1px 0 rgba(gray("black"), 0.1);
text-shadow: 0 1px 0 rgba(gray("black"), 0.5);
border-radius: 4px;
padding: 0.4rem 0.8rem;
background-color: rgba(gray("white"), 0.1);
@include media-breakpoint-up(md) {
padding: 0.8rem 1.2rem;
}
.input-group-prepend {
span.fa {
color: gray("white");
font-size: 1.5rem;
margin-right: 1rem;
padding-top: 1px;
}
}
.form-control {
height: 2rem;
background: none;
border: none;
color: gray("white");
display: block;
padding: 1px 2px 2px 2px;
box-shadow: none;
&::placeholder {
color: gray("white");
opacity: 0.5;
}
}
}
}
}
// Allow to scroll only on results, keeping static search box above
.search-container.has-results {
height: 100%;
.search-results {
max-height: calc(100vh - 47px - 6em);
overflow-y: hidden;
overflow-x: scroll;
overflow: auto;
background: url("../img/home-menu-bg-overlay.svg"),
linear-gradient(to bottom, gray("200"), gray("white"));
background-position: center;
background-size: cover;
}
}
}
}
// Scroll all but top bar
html .o_web_client .o_action_manager .o_action {
@include media-breakpoint-down(sm) {
overflow: auto;
.o_content {
overflow: visible;
}
}
max-width: 100%;
}
// Make enough space for search panel filters buttons
.o_control_panel {
// There is no media breakpoint for XL upper bound
@include media-breakpoint-up(lg) {
@media (max-width: 1360px) {
.o_cp_top_left,
.o_cp_bottom_left {
width: 40%;
}
.o_cp_top_right,
.o_cp_bottom_right {
width: 60%;
}
}
}
// For FULL HD devices
@media (min-width: 1900px) {
.o_cp_top_left,
.o_cp_bottom_left {
width: 60%;
}
.o_cp_top_right,
.o_cp_bottom_right {
width: 40%;
}
}
@include media-breakpoint-only(md) {
.o_search_options_hide_labels .o_dropdown_title {
display: none;
}
}
.o_cp_bottom_right {
height: 30px;
}
}
// Mobile Control panel (breadcrumbs, search box, buttons...)
@include media-breakpoint-down(sm) {
.o_control_panel {
// Avoid horizontal scrolling of control panel.
// It doesn't work on iOS Safari, but it looks similar as
// without this patch. With this patch it looks better for
// other browsers.
position: sticky;
left: 0;
z-index: 3;
// Arrange buttons to use space better
.o_cp_top_left,
.o_cp_top_right {
flex: 1 1 100%;
}
.o_cp_top_left {
flex-basis: 80%;
}
.o_cp_top_right {
flex-basis: 20%;
}
.o_cp_bottom {
position: relative; // Necessary for dropdown menu positioning
display: block;
margin: 0;
}
.o_cp_bottom_left {
float: left;
margin: 5px 0;
}
.o_cp_bottom_right {
float: right;
height: 30px;
padding-left: 10px;
margin: 5px 0;
}
.o_cp_bottom_right,
.o_cp_pager {
white-space: nowrap;
}
.o_cp_pager {
margin-bottom: 0;
}
.o_cp_bottom_left > .o_cp_action_menus {
padding-right: 0;
.o_dropdown_title,
.fa-chevron-right,
.fa-chevron-down {
display: none;
}
.o_dropdown_toggler_btn {
margin: 0px 2px;
}
@include media-breakpoint-down(xs) {
.o_dropdown {
position: static;
}
.dropdown-menu {
right: 0;
left: 0;
top: 35px;
}
}
}
// Hide all but 2 last breadcrumbs, and render 2nd-to-last as arrow
.breadcrumb-item {
&:not(.active) {
padding-left: 0;
}
&::before {
content: none;
padding-right: 0;
}
&:nth-last-of-type(1n + 3) {
display: none;
}
&:nth-last-of-type(2) {
&::before {
color: var(--primary);
content: "\f060"; // .fa-arrow-left
cursor: pointer;
font-family: FontAwesome;
}
a {
display: none;
}
}
}
// Ellipsize long breadcrumbs
.breadcrumb {
max-width: 100%;
text-overflow: ellipsis;
}
// In case you install `mail`, there is a mess on BS vs inline styles
// we need to fix
.o_cp_buttons .btn.d-block:not(.d-none) {
display: inline-block !important;
}
.o_searchview {
padding: 1px 0px 3px 0px;
&.o_searchview_mobile {
cursor: pointer;
}
&.o_searchview_quick {
display: flex;
flex: 1 1 auto;
align-items: center;
.o_searchview_input_container {
flex: 1 1 auto;
}
}
}
}
.o_calendar_view .o_calendar_widget {
.fc-timeGridDay-view .fc-axis,
.fc-timeGridWeek-view .fc-axis {
padding-left: 0px;
}
.fc-dayGridMonth-view {
padding-left: 0px;
.fc-week-number {
display: none;
}
}
.fc-dayGridYear-view {
padding-left: 0px;
> .fc-month-container > .fc-month {
width: 100%;
}
}
.fc-timeGridDay-view .fc-widget-header {
margin: 0 4px;
}
.fc-timeGridWeek-view .fc-widget-header {
word-spacing: 4em;
white-space: normal;
text-align: center;
}
}
.o_base_settings .o_setting_container {
display: block;
.settings_tab {
flex-flow: row nowrap;
padding-top: 0px;
.tab {
padding-right: 16px;
}
.selected {
background-color: #212529;
box-shadow: inset 0 -5px #7c7bad;
}
}
}
}
// Size of labels
.o_web_client {
&.o_chatter_position_sided {
.o_action_manager {
.o_content,
.modal-content {
@include media-breakpoint-up(xl, $o-extra-grid-breakpoints) {
.o_inner_group {
.o_td_label {
min-width: 260px !important;
}
}
}
@include media-breakpoint-between(lg, xl, $o-extra-grid-breakpoints) {
.o_group_col_6 {
width: 100% !important;
}
}
}
}
}
&:not(.o_chatter_position_sided) {
@include media-breakpoint-up(lg, $o-extra-grid-breakpoints) {
.o_action_manager {
.o_content,
.modal-content {
.o_inner_group {
.o_td_label {
min-width: 260px !important;
}
}
}
}
}
}
}
// Normal views
.o_content,
.modal-content {
max-width: 100%;
// Form views
.o_form_view {
.o_form_sheet {
max-width: calc(100% - 32px);
overflow-x: auto;
}
.o_FormRenderer_chatterContainer {
padding-top: 0;
.o_Activity_info {
flex-wrap: wrap;
}
.o_ActivityBox_title {
margin-bottom: 0;
}
.o_MessageList_separatorDate {
padding-bottom: 0;
}
}
// Sided chatter scrolling behavior
.o_Chatter {
height: fit-content;
.o_Chatter_fixedPanel {
position: sticky;
top: 0;
z-index: 1;
background-color: white;
padding-bottom: 10px;
}
.o_Chatter_scrollPanel {
overflow: initial;
}
}
// Sticky statusbar
.o_form_statusbar {
position: sticky;
top: 0;
z-index: 2;
}
// Support for long title (with ellipsis)
.oe_title {
span.o_field_widget:not(.oe_inline) {
max-width: 100%;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
width: initial;
&:active {
white-space: normal;
}
}
}
@include media-breakpoint-down(sm) {
min-width: auto;
// More buttons border
.oe_button_box {
.o_dropdown_more {
button:last-child {
border-right: 1px solid gray("400");
}
}
}
// Avoid overflow on forms with title and/or button box
.oe_title {
max-width: 100%;
}
.oe_button_box + .oe_title,
.oe_button_box + .oe_avatar + .oe_title {
width: 100%;
}
// Avoid overflow on modals
.o_form_sheet {
min-width: auto;
}
// Render website inputs properly in phones
.o_group .o_field_widget.o_text_overflow {
// Overrides another !important
width: auto !important;
}
// Make all input groups vertical
.o_group_col_6 {
width: 100%;
}
// Statusbar buttons dropdown for mobiles
.o_statusbar_buttons_dropdown {
border: {
bottom: 0;
radius: 0;
top: 0;
}
height: 100%;
}
.o_statusbar_buttons.dropdown-menu > .btn {
border-radius: 0;
border: 0;
width: 100%;
margin-bottom: 0.2rem;
&:last-child {
margin-bottom: 0;
}
}
.o_statusbar_status {
// Arrow from rightmost button exceeds allowed width
.o_arrow_button:first-child::before {
content: none;
display: none;
}
}
// Full width in form sheets
.o_form_sheet,
.o_FormRenderer_chatterContainer {
min-width: auto;
max-width: 98%;
}
// Settings pages
.app_settings_block {
.row {
margin: 0;
}
}
.o_FormRenderer_chatterContainer {
padding-top: initial;
// Display send button on small screens
.o_thread_composer {
padding-left: $o-mail-thread-avatar-size * 0.5;
.o_composer_button_send {
display: initial !important; // Forced in core
}
.o_chatter_avatar {
display: none;
}
}
.o_chatter_topbar {
> .o_topbar_right_area {
flex: 1 0 auto;
flex-wrap: wrap;
max-width: 100%;
// Display followers on small screens
.o_followers {
display: initial !important; // Forced in core
@include media-breakpoint-down(xs) {
padding-bottom: 50px;
}
}
}
}
}
}
}
//No content message improvements on mobile
@include media-breakpoint-down(md) {
.o_view_nocontent {
top: 80px;
}
.o_nocontent_help {
box-shadow: none;
}
.o_sample_data_disabled {
display: none;
}
}
// Sided chatter, if user wants
.o_chatter_position_sided & {
@include media-breakpoint-up(lg) {
.o_form_view:not(.o_form_nosheet) {
display: flex;
flex-flow: row nowrap;
height: 100%;
.o_form_sheet_bg {
flex: 1 1 auto;
overflow: auto;
> .o_form_sheet {
min-width: unset;
}
}
.o_FormRenderer_chatterContainer {
border-left: 1px solid gray("400");
flex: 0 0 $chatter_zone_width;
max-width: initial;
min-width: initial;
overflow: auto;
.o_chatter_header_container {
padding-top: $grid-gutter-width * 0.5;
top: 0;
position: sticky;
background-color: $o-view-background-color;
z-index: 1;
// Scrollable input text to avoid hide conversation & buttons
.o_composer_text_field {
max-height: 120px;
overflow-y: auto !important; /* Forced because Odoo uses inline style */
}
.o_attachments_list {
overflow: auto;
max-height: $o-mail-attachment-image-size * 3;
margin-top: 0.4em;
}
.o_attachments_previews {
overflow: auto;
max-height: $o-mail-attachment-image-size * 6;
}
}
}
}
}
}
}
// Sticky Header & Footer in List View
.o_list_view {
.table-responsive {
.o_list_table {
// th & td are here for compatibility with chrome
thead tr:nth-child(1) th {
position: sticky;
top: 0;
z-index: 1;
}
thead tr:nth-child(1) th {
background-color: $o-list-footer-bg-color;
}
tfoot,
tfoot tr:nth-child(1) td {
position: sticky;
bottom: 0;
}
tfoot tr:nth-child(1) td {
background-color: $o-list-footer-bg-color;
}
}
}
}
// Big checkboxes
.o_list_view {
.custom-checkbox:not(.o_boolean_toggle) {
margin-right: 10px;
.custom-control-label {
top: -6px;
&::after {
width: 24px;
height: 24px;
}
&::before {
outline: none !important;
border: 1px solid #4c4c4c;
width: 24px;
height: 24px;
}
}
}
}
// Waiting Cursor
.oe_wait {
cursor: progress;
}
// Attachment Viewer
.o_web_client.o_chatter_position_sided .o_Dialog_AttachmentViewer {
/* Show sided viewer on large screens */
@include media-breakpoint-up(lg) {
position: static;
.o_AttachmentViewer_main {
padding-bottom: 20px;
}
.o_AttachmentViewer {
// On-top of navbar
z-index: 10;
position: absolute;
right: 0;
top: 0;
bottom: 0;
margin-left: auto;
background-color: rgba(0, 0, 0, 0.7);
.o_AttachmentViewer_name {
display: contents;
}
width: $chatter_zone_width;
&.o_AttachmentViewer_maximized {
width: 100%;
}
/* Show/Hide control buttons (next, prev, etc..) */
&:hover .o_AttachmentViewer_buttonNavigation,
&:hover .o_AttachmentViewer_toolbar {
display: flex;
}
.o_AttachmentViewer_buttonNavigation,
.o_AttachmentViewer_toolbar {
display: none;
}
.o_AttachmentViewer_viewIframe {
width: 95%;
}
}
}
@include media-breakpoint-down(md) {
.o_AttachmentViewer_headerItemButtonMinimize,
.o_AttachmentViewer_headerItemButtonMaximize {
display: none;
}
}
}
/* Attachment Viewer Max/Min buttons only are useful in sided mode */
.o_web_client:not(.o_chatter_position_sided) {
.o_AttachmentViewer_headerItemButtonMinimize,
.o_AttachmentViewer_headerItemButtonMaximize {
display: none;
}
}
.o_control_panel {
// Filter Menu
// Cut long filters names in the filters menu
.o_filter_menu {
.o_menu_item {
width: auto;
@include media-breakpoint-up(md) {
max-width: 250px;
}
a {
overflow: hidden;
text-overflow: ellipsis;
}
}
}
// Enable scroll on dropdowns
.o_cp_buttons .dropdown-menu {
max-height: 70vh;
overflow-y: auto;
overflow-x: hidden;
}
// Dropdown with buttons to switch the view type
.o_cp_switch_buttons.show {
.dropdown-menu {
align-content: center;
display: flex;
flex-direction: row;
justify-content: space-around;
padding: 0;
.btn {
border: {
bottom: 0;
radius: 0;
top: 0;
}
font-size: 1.3em;
}
}
}
}
// Shortcut table ui improvement
.o_shortcut_table {
width: 100%;
}
<?xml version="1.0" encoding="UTF-8" ?>
<!-- Copyright 2018 Tecnativa - Jairo Llopis
License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). -->
<template>
<t t-extend="AppsMenu">
<!-- App icons must be clickable -->
<t t-jquery=".o_app" t-operation="attributes">
<attribute
name="t-attf-href"
t-translation="off"
>#menu_id=#{app.menuID}&amp;action_id=#{app.actionID}</attribute>
<attribute name="draggable" t-translation="off">false</attribute>
</t>
<!-- App icons should be more than a text -->
<t t-jquery=".o_app &gt; t" t-operation="replace">
<t t-call="web_responsive.AppIcon" />
</t>
<!-- Same hotkey as in EE -->
<t t-jquery=".full" t-operation="attributes">
<attribute name="accesskey">a</attribute>
</t>
<!-- Search bar -->
<t t-jquery="[t-as=app]" t-operation="before">
<div class="search-container align-items-center col-12">
<div class="search-input">
<div class="input-group">
<div class="input-group-prepend">
<span class="fa fa-search" />
</div>
<input
type="search"
autocomplete="off"
placeholder="Search menus..."
class="form-control"
/>
</div>
<div class="search-results ml-auto mr-auto rounded" />
</div>
</div>
</t>
</t>
<!-- Separate app icon template, for easier inheritance -->
<t t-name="web_responsive.AppIcon">
<img
class="o-app-icon"
draggable="false"
t-attf-src="data:image/png;base64,#{app.web_icon_data}"
/>
<span class="o-app-name">
<t t-esc="app.name" />
</span>
</t>
<!-- A search result -->
<t t-name="web_responsive.MenuSearchResults">
<t t-foreach="results" t-as="result">
<t t-set="menu" t-value="widget._menuInfo(result.original)" />
<a
t-attf-class="o-menu-search-result dropdown-item col-12 ml-auto mr-auto #{result_first ? 'active' : ''}"
t-attf-style="background-image:url('data:image/png;base64,#{menu.web_icon_data}')"
t-attf-href="#menu_id=#{menu.id}&amp;action_id=#{menu.action_id}"
t-att-data-menu-id="menu.id"
t-att-data-action-id="menu.action_id"
t-att-data-parent-id="menu.parent_id[0]"
draggable="false"
t-raw="result.string"
/>
</t>
</t>
</template>
<?xml version="1.0" encoding="UTF-8" ?>
<!-- Copyright 2019 Tecnativa - Alexandre Díaz
Copyright 2021 Sergey Shebanin
License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). -->
<template>
<t t-inherit="mail.Dialog" t-inherit-mode="extension" owl="1">
<xpath expr="//div[hasclass('o_Dialog')]" position="attributes">
<attribute
name="t-attf-class"
t-translation="off"
>o_Dialog_{{dialog.record['constructor'].name}}</attribute>
</xpath>
</t>
<t t-inherit="mail.AttachmentViewer" t-inherit-mode="extension" owl="1">
<xpath expr="//div[hasclass('o_AttachmentViewer')]" position="attributes">
<attribute
name="t-att-class"
t-translation="off"
>state.maximized ? 'o_AttachmentViewer_maximized' : ''</attribute>
</xpath>
<xpath
expr="//div[hasclass('o_AttachmentViewer_header')]/div[hasclass('o-autogrow')]"
position="after"
>
<div
t-if="!state.maximized"
class="o_AttachmentViewer_headerItem o_AttachmentViewer_headerItemButton o_AttachmentViewer_headerItemButtonMaximize"
t-on-click="state.maximized=true"
role="button"
title="Maximize"
aria-label="Maximize"
>
<i class="fa fa-fw fa-window-maximize" role="img" />
</div>
<div
t-if="state.maximized"
class="o_AttachmentViewer_headerItem o_AttachmentViewer_headerItemButton o_AttachmentViewer_headerItemButtonMinimize"
t-on-click="state.maximized=false"
role="button"
title="Minimize"
aria-label="Minimize"
>
<i class="fa fa-fw fa-window-minimize" role="img" />
</div>
</xpath>
</t>
</template>
<?xml version="1.0" encoding="UTF-8" ?>
<!-- Copyright 2021 Sergey Shebanin
License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). -->
<templates>
<t t-inherit="web.ControlPanel" t-inherit-mode="extension" owl="1">
<xpath expr="//nav[hasclass('o_cp_switch_buttons')]" position="replace">
<nav
t-if="props.views.length gt 1"
class="btn-group o_cp_switch_buttons"
role="toolbar"
aria-label="View switcher"
>
<t
t-set="collapse_switchview"
t-value="device.size_class &lt;= device.SIZES.LG"
/>
<button
t-if="collapse_switchview"
class="btn btn-link btn-sm"
data-toggle="dropdown"
aria-expanded="false"
>
<span
t-attf-class="fa fa-lg o_switch_view o_{{ env.view.type }} {{ props.views.filter(view => view.type === env.view.type)[0].icon }}"
/>
</button>
<ul
t-if="collapse_switchview"
class="dropdown-menu dropdown-menu-right list-inline"
>
<li t-foreach="props.views" t-as="view" t-key="view.type">
<t t-call="web.ViewSwitcherButton" />
</li>
</ul>
<t
t-if="!collapse_switchview"
t-foreach="props.views"
t-as="view"
t-key="view.type"
>
<t t-call="web.ViewSwitcherButton" />
</t>
</nav>
</xpath>
<xpath expr="//div[hasclass('o_searchview')]" position="replace">
<div
t-if="props.withSearchBar"
class="o_searchview"
t-att-class="state.mobileSearchMode == 'quick' ? 'o_searchview_quick' : 'o_searchview_mobile'"
role="search"
aria-autocomplete="list"
t-on-click.self="state.mobileSearchMode = device.isMobile ? 'quick' : ''"
>
<t t-if="!device.isMobile">
<i
class="o_searchview_icon fa fa-search"
title="Search..."
role="img"
aria-label="Search..."
/>
<SearchBar fields="fields" />
</t>
<t t-if="device.isMobile and state.mobileSearchMode == 'quick'">
<button
class="btn btn-link fa fa-arrow-left"
t-on-click.stop="state.mobileSearchMode = ''"
/>
<SearchBar fields="fields" />
<button
class="btn fa fa-filter"
t-on-click.stop="state.mobileSearchMode = 'full'"
/>
</t>
<t
t-if="device.isMobile and state.mobileSearchMode == 'full'"
t-call="web_responsive.MobileSearchView"
/>
<t t-if="device.isMobile and state.mobileSearchMode == ''">
<button
class="btn btn-link fa fa-search"
t-on-click.stop="state.mobileSearchMode = 'quick'"
/>
</t>
</div>
</xpath>
<xpath expr="//div[hasclass('o_cp_top_left')]" position="attributes">
<attribute
name="t-att-class"
t-translation="off"
>device.isMobile and state.mobileSearchMode == 'quick' ? 'o_hidden' : ''</attribute>
</xpath>
<xpath expr="//div[hasclass('o_search_options')]" position="attributes">
<attribute name="t-if" t-translation="off">!device.isMobile</attribute>
<attribute
name="t-att-class"
t-translation="off"
>device.size_class == device.SIZES.MD ? 'o_search_options_hide_labels' : ''</attribute>
</xpath>
</t>
<t t-name="web_responsive.MobileSearchView" owl="1">
<div class="o_mobile_search">
<div class="o_mobile_search_header">
<span
class="o_mobile_search_close float-left mt16 mb16 mr8 ml16"
t-on-click.stop="state.mobileSearchMode = 'quick'"
>
<i class="fa fa-arrow-left" />
<strong class="float-right ml8">FILTER</strong>
</span>
<span
class="float-right o_mobile_search_clear_facets mt16 mr16"
t-on-click.stop="model.dispatch('clearQuery')"
>
<t>CLEAR</t>
</span>
</div>
<SearchBar fields="fields" />
<div class="o_mobile_search_filter o_search_options mb8 mt8 ml16 mr16">
<FilterMenu
t-if="props.searchMenuTypes.includes('filter')"
class="o_filter_menu"
fields="fields"
/>
<GroupByMenu
t-if="props.searchMenuTypes.includes('groupBy')"
class="o_group_by_menu"
fields="fields"
/>
<ComparisonMenu
t-if="props.searchMenuTypes.includes('comparison') and model.get('filters', f => f.type === 'comparison').length"
class="o_comparison_menu"
/>
<FavoriteMenu
t-if="props.searchMenuTypes.includes('favorite')"
class="o_favorite_menu"
/>
</div>
<div
class="btn btn-primary o_mobile_search_show_result fixed-bottom"
t-on-click.stop="state.mobileSearchMode = ''"
>
<t>SEE RESULT</t>
</div>
</div>
</t>
</templates>
<?xml version="1.0" encoding="UTF-8" ?>
<!-- Copyright 2019 Tecnativa - Alexandre Díaz
License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). -->
<template>
<t t-extend="mail.discuss.ControlButtons">
<t
t-jquery=".o_mail_discuss_button_multi_user_channel"
t-operation="attributes"
>
<attribute name="class" t-translation="off">
btn btn-secondary o_mail_discuss_button_multi_user_channel d-md-block
d-none
</attribute>
</t>
</t>
</template>
<?xml version="1.0" encoding="utf-8" ?>
<!--
Copyright 2017 LasLabs Inc.
Copyright 2018 Alexandre Díaz
Copyright 2018 Tecnativa - Jairo Llopis
License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
-->
<templates id="form_view" xml:space="preserve">
<!-- Template for buttons that display only the icon in xs -->
<t t-name="web_responsive.icon_button">
<i t-attf-class="fa fa-#{icon}" t-att-title="label" />
<span class="d-none d-sm-inline" t-esc="label" />
</t>
<t t-name="web_responsive.MenuStatusbarButtons">
<div class="dropdown">
<button
class="o_statusbar_buttons_dropdown btn btn-secondary dropdown-toggle"
type="button"
data-toggle="dropdown"
aria-haspopup="true"
aria-expanded="false"
>
<t t-call="web_responsive.icon_button">
<t t-set="icon" t-value="'cogs'" />
<t t-set="label">Quick actions</t>
</t>
</button>
<!-- A div.o_statusbar_buttons.dropdown-menu
is appended here from JS -->
</div>
</t>
<t t-extend="FormView.buttons">
<!-- Change "Edit" button hotkey to "E" -->
<t t-jquery=".o_form_button_edit" t-operation="attributes">
<attribute name="accesskey">e</attribute>
</t>
<!-- Change "Discard" button hotkey to "D" -->
<t t-jquery=".o_form_button_cancel" t-operation="attributes">
<attribute name="accesskey">d</attribute>
</t>
<!-- Add responsive icons to buttons -->
<t t-jquery=".o_form_button_edit" t-operation="inner">
<t t-call="web_responsive.icon_button">
<t t-set="icon" t-value="'pencil'" />
<t t-set="label">Edit</t>
</t>
</t>
<t t-jquery=".o_form_button_create" t-operation="inner">
<t t-call="web_responsive.icon_button">
<t t-set="icon" t-value="'plus'" />
<t t-set="label">Create</t>
</t>
</t>
<t t-jquery=".o_form_button_save" t-operation="inner">
<t t-call="web_responsive.icon_button">
<t t-set="icon" t-value="'check'" />
<t t-set="label">Save</t>
</t>
</t>
<t t-jquery=".o_form_button_cancel" t-operation="inner">
<t t-call="web_responsive.icon_button">
<t t-set="icon" t-value="'times'" />
<t t-set="label">Discard</t>
</t>
</t>
</t>
<t t-extend="KanbanView.buttons">
<!-- Add responsive icons to buttons -->
<t t-jquery="button" t-operation="inner">
<t t-call="web_responsive.icon_button">
<t t-set="icon" t-value="'plus'" />
<t t-set="label" t-value="create_text || _t('Create')" />
</t>
</t>
</t>
<t t-extend="ListView.buttons">
<!-- Change "Discard" button hotkey to "D" -->
<t t-jquery=".o_list_button_discard" t-operation="attributes">
<attribute name="accesskey">d</attribute>
</t>
<!-- Add responsive icons to buttons -->
<t t-jquery=".o_list_button_add" t-operation="inner">
<t t-call="web_responsive.icon_button">
<t t-set="icon" t-value="'plus'" />
<t t-set="label">Create</t>
</t>
</t>
<t t-jquery=".o_list_button_save" t-operation="inner">
<t t-call="web_responsive.icon_button">
<t t-set="icon" t-value="'check'" />
<t t-set="label">Save</t>
</t>
</t>
<t t-jquery=".o_list_button_discard" t-operation="inner">
<t t-call="web_responsive.icon_button">
<t t-set="icon" t-value="'times'" />
<t t-set="label">Discard</t>
</t>
</t>
</t>
<t t-extend="CalendarView.navigation_buttons">
<!-- Add responsive icons to buttons -->
<t t-jquery=".o_calendar_button_today" t-operation="inner">
<t t-call="web_responsive.icon_button">
<t t-set="icon" t-value="'calendar-check-o'" />
<t t-set="label">Today</t>
</t>
</t>
</t>
</templates>
<?xml version="1.0" encoding="UTF-8" ?>
<templates id="template" xml:space="preserve">
<div t-extend="UserMenu.shortcuts">
<t
t-jquery="table.o_shortcut_table > tbody > tr > td:nth-child(2) > span:first-child"
t-operation="after"
>
+ <span class="o_key">Shift</span>
</t>
</div>
</templates>
<?xml version="1.0" encoding="UTF-8" ?>
<!-- Copyright 2017-2018 Tecnativa - Jairo Llopis
License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). -->
<templates>
<t t-extend="Menu">
<t t-jquery=".o_menu_apps" t-operation="after">
<!-- Hamburger button to show submenus in sm screens -->
<button
class="o-menu-toggle d-md-none"
data-toggle="collapse"
data-target=".o_main_navbar .o_menu_sections"
>
<i class="fa fa-bars" />
</button>
</t>
</t>
</templates>
<?xml version="1.0" encoding="UTF-8" ?>
<!-- Copyright 2021 Sergey Shebanin
License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). -->
<templates>
<t t-inherit="web.SearchPanel" t-inherit-mode="extension" owl="1">
<xpath expr="//div[hasclass('o_search_panel')]" position="inside">
<div
t-if="device.isMobile"
class="o_search_panel_summary"
t-on-click.stop="state.mobileSearch = true"
>
<div class="d-flex flex-wrap align-items-center">
<i class="fa fa-fw fa-filter mr-1" />
<t t-set="filters" t-value="getActiveSummary()" />
<span t-foreach="filters" t-as="filter" class="mx-1">
<i
t-if="filter.icon"
t-attf-class="fa {{ filter.icon }} mr-2"
t-att-style="filter.color and ('color: ' + filter.color)"
/>
<t
t-esc="filter.values.join(filter.type == 'category' ? ' / ' : ', ')"
/>
</span>
<t t-if="!filters.length">All</t>
</div>
</div>
<div
class="o_search_panel_content"
t-att-class="device.isMobile ? (state.mobileSearch ? 'o_mobile_search' : 'd-none'): ''"
/>
</xpath>
<xpath expr="//div[hasclass('o_search_panel_content')]" position="inside">
<div t-if="device.isMobile" class="o_mobile_search_header">
<span
class="o_mobile_search_close float-left mt16 mb16 mr8 ml16"
t-on-click.stop="state.mobileSearch = false"
>
<i class="fa fa-arrow-left" />
<strong class="float-right ml8">FILTER</strong>
</span>
</div>
<xpath expr="//section" position="move" />
<div
t-if="device.isMobile"
class="btn btn-primary o_mobile_search_show_result fixed-bottom"
t-on-click.stop="state.mobileSearch = false"
>
<t>SEE RESULT</t>
</div>
</xpath>
</t>
</templates>
from . import test_res_users
# Copyright 2018 Alexandre Díaz
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
from odoo.tests import common
class TestResUsers(common.TransactionCase):
def test_chatter_position_wr(self):
user_public = self.env.ref("base.public_user")
self.assertEqual(user_public.chatter_position, "sided")
user_public.with_user(user_public).write({"chatter_position": "normal"})
self.assertEqual(user_public.chatter_position, "normal")
<?xml version="1.0" encoding="utf-8" ?>
<!--
Copyright 2016 LasLabs Inc.
@author Dave Lasley <dave@laslabs.com>
License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
-->
<odoo>
<template
id="assets_backend"
name="Open Mobile Assets"
inherit_id="web.assets_backend"
>
<xpath expr="//link[last()]" position="after">
<link
type="text/css"
rel="stylesheet"
href="/web_responsive/static/src/scss/web_responsive.scss"
/>
<link
type="text/css"
rel="stylesheet"
href="/web_responsive/static/src/scss/search_view_mobile.scss"
/>
<link
type="text/css"
rel="stylesheet"
href="/web_responsive/static/src/scss/kanban_view_mobile.scss"
/>
</xpath>
<xpath expr="//script[last()]" position="after">
<script
type="application/javascript"
src="/web_responsive/static/src/js/web_responsive.js"
/>
<script
type="application/javascript"
src="/web_responsive/static/src/js/kanban_renderer_mobile.js"
/>
</xpath>
</template>
</odoo>
<?xml version="1.0" ?>
<!--
Copyright 2018
@author Alexanre Díaz <dev@redneboa.es>
License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
-->
<odoo>
<record id="view_users_form_simple_modif" model="ir.ui.view">
<field name="model">res.users</field>
<field name="inherit_id" ref="base.view_users_form_simple_modif" />
<field name="arch" type="xml">
<xpath expr="//field[@name='email']" position="after">
<field name="chatter_position" readonly="0" />
</xpath>
</field>
</record>
</odoo>
<?xml version="1.0" encoding="utf-8" ?>
<!--
Copyright 2018 Alexandre Díaz
License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
-->
<odoo>
<template
id="webclient_bootstrap"
inherit_id="web.webclient_bootstrap"
name="App Drawer - Web Client"
>
<xpath expr="//t[@t-set='body_classname']" position="attributes">
<attribute
name="t-value"
add="+ ' o_chatter_position_' + (request.env.user.chatter_position or 'normal')"
separator=" "
/>
</xpath>
</template>
<template
id="responsive_web_layout"
inherit_id="web.layout"
name="Responsive Layout"
>
<xpath expr="//meta[last()]" position="after">
<meta
name="viewport"
content="width=device-width, initial-scale=1, user-scalable=no"
/>
</xpath>
</template>
</odoo>
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!