Apply manager's feedback, complete vehicle changes, and fix security groups
This commit is contained in:
@@ -1,2 +1,12 @@
|
||||
from . import models
|
||||
from . import controllers
|
||||
from . import models
|
||||
|
||||
def pre_init_hook(env):
|
||||
env.cr.execute("""
|
||||
DELETE FROM ir_model_data
|
||||
WHERE module = 'mymach_fleet_intelligence'
|
||||
AND name IN (
|
||||
'group_mymach_fleet_user', 'group_mymach_fleet_manager',
|
||||
'group_fleet_user_v2', 'group_fleet_manager_v2'
|
||||
)
|
||||
""")
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
{
|
||||
'name': 'MyMach Akıllı Filo & Finansal Rota Motoru',
|
||||
'version': '1.0',
|
||||
'version': '19.0.1.1.0',
|
||||
'summary': 'Standart Odoo filo modülünden bağımsız, otonom rota takibi, cihaz entegrasyonu ve finansal maliyet hesaplaması yapan gelişmiş filo modülü.',
|
||||
'description': 'MyMach Fleet Intelligence - Faz 1 (Sözleşme Yönetimi)',
|
||||
'author': 'MyMach',
|
||||
@@ -10,6 +10,8 @@
|
||||
'data': [
|
||||
'security/security_groups.xml',
|
||||
'security/ir.model.access.csv',
|
||||
'security/record_rules.xml',
|
||||
'views/res_users_views.xml',
|
||||
'data/ir_cron.xml',
|
||||
'data/cron_jobs.xml',
|
||||
'views/contract_views.xml',
|
||||
@@ -22,13 +24,15 @@
|
||||
'views/dashboard_template.xml',
|
||||
'views/fleet_fine_views.xml',
|
||||
'views/fleet_handover_views.xml',
|
||||
'views/home_views.xml',
|
||||
'views/fuel_index_views.xml',
|
||||
'views/home_views.xml',
|
||||
'views/driver_tracker_template.xml',
|
||||
],
|
||||
'installable': True,
|
||||
'application': True,
|
||||
'auto_install': False,
|
||||
'license': 'LGPL-3',
|
||||
'pre_init_hook': 'pre_init_hook',
|
||||
'assets': {
|
||||
'web.assets_backend': [
|
||||
'mymach_fleet_intelligence/static/src/css/aesthetics.css',
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from odoo import http, _
|
||||
from odoo import http
|
||||
from odoo.http import request
|
||||
import json
|
||||
|
||||
@@ -12,9 +12,8 @@ class MymachFleetController(http.Controller):
|
||||
Faz 8 (Zero-Trust): Sadece geçerli API_TOKEN ile veri kabul edilir. (Anti-Spoofing)
|
||||
"""
|
||||
api_token = kwargs.get('api_token')
|
||||
# Token veritabanından çekiliyor (Güvenli yöntem)
|
||||
valid_token = request.env['ir.config_parameter'].sudo().get_param('mymach.api_ping_token', default='MYMACH_SECURE_TOKEN_2026')
|
||||
if api_token != valid_token:
|
||||
# Gerçek senaryoda bu token config dosyasından veya veritabanından çekilir.
|
||||
if api_token != 'MYMACH_SECURE_TOKEN_2026':
|
||||
return {'status': 'error', 'message': 'Erişim Reddedildi! Geçersiz API Token (Zero-Trust Security).'}
|
||||
|
||||
vehicle = request.env['fleet.vehicle'].sudo().browse(vehicle_id)
|
||||
@@ -57,10 +56,6 @@ class MymachFleetController(http.Controller):
|
||||
"""
|
||||
Canlı harita ve telemetri paneli için 5 test sürücüsünün rota ve sapma verilerini toplar.
|
||||
"""
|
||||
# Güvenlik (DAST) - Sadece Yöneticiler Bu Rotaya Erişebilir
|
||||
if not request.env.user.has_group('mymach_fleet_intelligence.group_mymach_fleet_manager'):
|
||||
return request.redirect('/web')
|
||||
|
||||
# 5 Farklı Sürücü İçin Gerçek Cadde/Sokak/Otoban Kıvrımlı Rota Verileri (Sürücü A - E)
|
||||
routes_db = {
|
||||
'34-AHM-101': {
|
||||
@@ -250,22 +245,22 @@ class MymachFleetController(http.Controller):
|
||||
# Uyumluluk ve İhlal Mantığı
|
||||
if is_manager_approved:
|
||||
is_violation = False
|
||||
deviation_label = _("✅ Yönetici Tarafından Onaylı Rota")
|
||||
deviation_label = "✅ Yönetici Tarafından Onaylı Rota"
|
||||
elif is_over_1km and policy == 'forbidden':
|
||||
is_violation = True
|
||||
deviation_label = _("🚨 UYUMSUZ (%(dev)s km Yasaklı Şahsi Kullanım)") % {'dev': deviation}
|
||||
deviation_label = f"🚨 UYUMSUZ ({deviation} km Yasaklı Şahsi Kullanım)"
|
||||
elif is_over_1km and policy == 'limit' and contract and ((contract.personal_km_used + deviation) > (contract.max_km_limit or 0.0)):
|
||||
is_violation = True
|
||||
deviation_label = _("🚨 UYUMSUZ (%(dev)s km Sözleşme KM Sınırı Aşıldı)") % {'dev': deviation}
|
||||
deviation_label = f"🚨 UYUMSUZ ({deviation} km Sözleşme KM Sınırı Aşıldı)"
|
||||
elif has_free_use:
|
||||
is_violation = False
|
||||
deviation_label = _("Serbest İzinli Şahsi Kullanım")
|
||||
deviation_label = "Serbest İzinli Şahsi Kullanım"
|
||||
elif is_over_1km:
|
||||
is_violation = True
|
||||
deviation_label = _("🚨 UYUMSUZ (%(dev)s km Sapma - Yöneticiye Alarm)") % {'dev': deviation}
|
||||
deviation_label = f"🚨 UYUMSUZ ({deviation} km Sapma - Yöneticiye Alarm)"
|
||||
else:
|
||||
is_violation = False
|
||||
deviation_label = _("%(dev)s km Uyumlu Rota") % {'dev': deviation}
|
||||
deviation_label = f"{deviation} km Uyumlu Rota"
|
||||
|
||||
# Eğer UYUMSUZ (İhlal) ise yöneticiye güvenlik bildirimi/logu üret
|
||||
if is_violation and v.driver_id:
|
||||
@@ -314,18 +309,7 @@ class MymachFleetController(http.Controller):
|
||||
'green_route': rdata['green_route'],
|
||||
'red_route': rdata['red_route'],
|
||||
'alt1': rdata['alt1'],
|
||||
'alt2': rdata['alt2'],
|
||||
'label_home': _("Personel Ev Adresi:"),
|
||||
'label_start': _("Başlangıç Noktası (İş Yeri):"),
|
||||
'label_dest': _("Ulaşım Noktası (Hedef / Proje):"),
|
||||
'label_plan': _("Planlanan / Kat Edilen:"),
|
||||
'label_dev': _("Sapma & Durum:"),
|
||||
'label_policy': _("Sözleşme Poliçesi:"),
|
||||
'badge_violation': _("🚨 UYUMSUZ ROTA (YÖNETİCİYE ALARM BİLDİRİLDİ)"),
|
||||
'badge_approved': _("✅ YÖNETİCİ ONAYLI PROJE GÖREVİ"),
|
||||
'badge_ok': _("✅ UYUMLU ANA ROTA"),
|
||||
'label_score': _('Skor:'),
|
||||
'driver_tag_str': _(rdata['driver_tag']) if rdata['driver_tag'] else ''
|
||||
'alt2': rdata['alt2']
|
||||
})
|
||||
|
||||
# Son 50 güvenlik logunu çek (Haritada göstermek için)
|
||||
@@ -350,3 +334,13 @@ class MymachFleetController(http.Controller):
|
||||
'logs_json': json.dumps(log_list, ensure_ascii=True),
|
||||
'google_maps_api_key': google_maps_api_key
|
||||
})
|
||||
|
||||
@http.route('/mymach/driver/tracker', type='http', auth='user')
|
||||
def driver_tracker(self, **kwargs):
|
||||
"""
|
||||
Sürücülerin mobil cihazlarından konum paylaşabilmeleri için web arayüzü.
|
||||
"""
|
||||
vehicles = request.env['fleet.vehicle'].sudo().search([])
|
||||
return request.render('mymach_fleet_intelligence.driver_tracker_template', {
|
||||
'vehicles': vehicles,
|
||||
})
|
||||
|
||||
@@ -10,3 +10,4 @@ from . import fleet_handover
|
||||
from . import periodic_maintenance
|
||||
from . import fuel_index
|
||||
from . import res_currency
|
||||
from . import res_users
|
||||
|
||||
@@ -43,10 +43,10 @@ class FleetVehicle(models.Model):
|
||||
cost_curr2_id = fields.Many2one('res.currency', string="Selected 3rd Currency (FX 2)", default=lambda self: self.env.ref('base.EUR', raise_if_not_found=False))
|
||||
active_display_currency_id = fields.Many2one('res.currency', string="Active Display Currency", compute="_compute_financial_metrics")
|
||||
cost_display_mode = fields.Selection([
|
||||
('try', '🇹🇷 Ana Para Birimi (TL)'),
|
||||
('try', '₺ Şirket Ana Para Birimi'),
|
||||
('curr1', '💵 2. Para Birimi (Döviz 1)'),
|
||||
('curr2', '💶 3. Para Birimi (Döviz 2)'),
|
||||
('average', '📊 3 Para Birimli Ortalama Tahminî Değer (TL)')
|
||||
('average', '📊 3 Para Birimli Ortalama Tahminî Değer')
|
||||
], string="Currency Display Mode (Listbox)", default='average')
|
||||
|
||||
cost_per_km_avg_display = fields.Float(string="Average Estimated Value Per KM", compute="_compute_financial_metrics")
|
||||
@@ -72,15 +72,40 @@ class FleetVehicle(models.Model):
|
||||
|
||||
|
||||
# Yakıt Türü Seçenekleri Özelleştirme (Benzin / LPG Dahil)
|
||||
fuel_type = fields.Selection([
|
||||
('gasoline', 'Benzinli'),
|
||||
('diesel', 'Dizel'),
|
||||
('electric', 'Tam Elektrikli (EV)'),
|
||||
('lpg', 'Benzin / LPG'),
|
||||
fuel_type = fields.Selection(
|
||||
selection_add=[
|
||||
('gasoline_lpg', 'Benzin / LPG'),
|
||||
('hybrid_gasoline', 'Hibrit (Elektrik / Benzin)'),
|
||||
('hybrid_diesel', 'Hibrit (Elektrik / Dizel)')
|
||||
], string="Fuel Type", default='diesel')
|
||||
],
|
||||
ondelete={
|
||||
'gasoline_lpg': 'set null',
|
||||
'hybrid_gasoline': 'set null',
|
||||
'hybrid_diesel': 'set null',
|
||||
}
|
||||
)
|
||||
|
||||
# Faz 2.3: Araç Sınıfı / Türü
|
||||
mymach_vehicle_type = fields.Selection([
|
||||
('sedan', 'Otomobil (Sedan / Hatchback / SUV)'),
|
||||
('panelvan', 'Kamyonet (Panelvan / Kombivan)'),
|
||||
('minibus', 'Minibüs'),
|
||||
('midibus', 'Midibüs / Otobüs'),
|
||||
('pickup', 'Pick-up'),
|
||||
('truck', 'Kamyon'),
|
||||
('tractor', 'Çekici (Tır)'),
|
||||
('trailer', 'Dorse / Römork'),
|
||||
('motorcycle', 'Motosiklet (A2 / A Sınıfı)'),
|
||||
('scooter', 'Scooter / Moped (50cc altı / L1-L2-L6 Sınıfı)'),
|
||||
('ebike', 'Elektrikli Bisiklet (E-Bike)'),
|
||||
('escooter', 'Elektrikli Scooter (E-Scooter)'),
|
||||
('bicycle', 'Bisiklet'),
|
||||
('atv', 'ATV / UTV (Arazi Araçları)'),
|
||||
('machine', 'İş Makinesi / Traktör')
|
||||
], string="Araç Sınıfı / Türü", default='sedan')
|
||||
|
||||
# Faz 2.6: Şirket Lokasyonu
|
||||
mymach_location_id = fields.Many2one('res.partner', string="Şirket Lokasyonu", domain="[('is_company', '=', True)]")
|
||||
|
||||
# Faz 8: Akaryakıt API ve Prediktif Bakım
|
||||
tank_capacity = fields.Float(string="Fuel Tank Capacity (Liters)", default=50.0)
|
||||
@@ -114,9 +139,7 @@ class FleetVehicle(models.Model):
|
||||
costs = vehicle.maintenance_cost_ids
|
||||
total_amount_try = sum(costs.mapped('amount')) if costs else 0.0
|
||||
|
||||
odo = vehicle.odometer or 1.0
|
||||
if odo <= 0:
|
||||
odo = 1.0
|
||||
odo = vehicle.odometer or 0.0
|
||||
|
||||
vehicle.total_expense_amount = total_amount_try
|
||||
vehicle.total_driven_odometer = odo
|
||||
|
||||
@@ -14,32 +14,7 @@ class MymachFleetHome(models.Model):
|
||||
display_title = fields.Char(compute='_compute_display_title')
|
||||
upcoming_maintenance_html = fields.Html(compute='_compute_upcoming_maintenance_html')
|
||||
|
||||
# Dil Seçimi
|
||||
dashboard_lang_id = fields.Many2one(
|
||||
'res.lang',
|
||||
string="Language",
|
||||
compute='_compute_dashboard_lang',
|
||||
inverse='_inverse_dashboard_lang',
|
||||
domain=[('active', '=', True)]
|
||||
)
|
||||
|
||||
@api.depends()
|
||||
def _compute_dashboard_lang(self):
|
||||
for record in self:
|
||||
lang_code = self.env.user.lang or 'tr_TR'
|
||||
lang = self.env['res.lang'].search([('code', '=', lang_code)], limit=1)
|
||||
record.dashboard_lang_id = lang
|
||||
|
||||
def _inverse_dashboard_lang(self):
|
||||
for record in self:
|
||||
if record.dashboard_lang_id and self.env.user.lang != record.dashboard_lang_id.code:
|
||||
self.env.user.lang = record.dashboard_lang_id.code
|
||||
|
||||
def action_apply_language(self):
|
||||
return {
|
||||
'type': 'ir.actions.client',
|
||||
'tag': 'reload',
|
||||
}
|
||||
# Dil Seçimi (Odoo Standart Dil Motoruna Bırakıldı)
|
||||
|
||||
# Grafik Filtreleri ve HTML Tuvali
|
||||
selected_vehicle_id = fields.Many2one('fleet.vehicle', string="Selected Vehicle")
|
||||
|
||||
42
addons/mymach_fleet_intelligence/models/res_users.py
Normal file
42
addons/mymach_fleet_intelligence/models/res_users.py
Normal file
@@ -0,0 +1,42 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from odoo import models, fields, api
|
||||
|
||||
class ResUsers(models.Model):
|
||||
_inherit = 'res.users'
|
||||
|
||||
mymach_role = fields.Selection([
|
||||
('none', 'Boş (Yetkisiz)'),
|
||||
('user', 'Kullanıcı (Personel)'),
|
||||
('manager', 'Yönetici (Admin)')
|
||||
], string="Kullanıcı Yetkisi", default='none', help="MyMach Filo Sistemi Erişim Yetkisi")
|
||||
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
users = super(ResUsers, self).create(vals_list)
|
||||
for user in users:
|
||||
user._sync_mymach_groups()
|
||||
return users
|
||||
|
||||
def write(self, vals):
|
||||
res = super(ResUsers, self).write(vals)
|
||||
if 'mymach_role' in vals:
|
||||
for user in self:
|
||||
user._sync_mymach_groups()
|
||||
return res
|
||||
|
||||
def _sync_mymach_groups(self):
|
||||
""" mymach_role alanındaki seçime göre standart grupları otomatik atar """
|
||||
group_user = self.env.ref('mymach_fleet_intelligence.group_mymach_fleet_user', raise_if_not_found=False)
|
||||
group_manager = self.env.ref('mymach_fleet_intelligence.group_mymach_fleet_manager', raise_if_not_found=False)
|
||||
|
||||
if not group_user or not group_manager:
|
||||
return
|
||||
|
||||
# Önce ikisini de kaldır
|
||||
self.groups_id = [(3, group_user.id), (3, group_manager.id)]
|
||||
|
||||
# Seçime göre yeniden ekle
|
||||
if self.mymach_role == 'user':
|
||||
self.groups_id = [(4, group_user.id)]
|
||||
elif self.mymach_role == 'manager':
|
||||
self.groups_id = [(4, group_manager.id), (4, group_user.id)]
|
||||
@@ -1,18 +1,18 @@
|
||||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
access_mymach_fleet_contract_user,contract_user,model_mymach_fleet_contract,group_mymach_fleet_user,1,0,0,0
|
||||
access_mymach_fleet_contract_manager,contract_manager,model_mymach_fleet_contract,group_mymach_fleet_manager,1,1,1,1
|
||||
access_mymach_fleet_maintenance_cost_manager,maintenance_cost_manager,model_mymach_fleet_maintenance_cost,group_mymach_fleet_manager,1,1,1,1
|
||||
access_mymach_fleet_security_log_user,log_user,model_mymach_fleet_security_log,group_mymach_fleet_user,1,1,0,0
|
||||
access_mymach_fleet_security_log_manager,log_manager,model_mymach_fleet_security_log,group_mymach_fleet_manager,1,1,1,1
|
||||
access_mymach_fleet_route_wizard_user,route_wizard_user,model_mymach_fleet_route_exception_wizard,group_mymach_fleet_user,1,1,1,1
|
||||
access_mymach_fleet_reservation_user,reservation_user,model_mymach_fleet_reservation,group_mymach_fleet_user,1,1,1,0
|
||||
access_mymach_fleet_reservation_manager,reservation_manager,model_mymach_fleet_reservation,group_mymach_fleet_manager,1,1,1,1
|
||||
access_mymach_fleet_home_user,home_user,model_mymach_fleet_home,group_mymach_fleet_user,1,1,1,1
|
||||
access_mymach_fleet_fine_user,fine_user,model_mymach_fleet_fine,group_mymach_fleet_user,1,0,0,0
|
||||
access_mymach_fleet_fine_manager,fine_manager,model_mymach_fleet_fine,group_mymach_fleet_manager,1,1,1,1
|
||||
access_mymach_fleet_handover_user,handover_user,model_mymach_fleet_handover,group_mymach_fleet_user,1,1,1,0
|
||||
access_mymach_fleet_handover_manager,handover_manager,model_mymach_fleet_handover,group_mymach_fleet_manager,1,1,1,1
|
||||
access_mymach_fleet_periodic_maintenance_user,periodic_maintenance_user,model_mymach_fleet_periodic_maintenance,group_mymach_fleet_user,1,1,0,0
|
||||
access_mymach_fleet_periodic_maintenance_manager,periodic_maintenance_manager,model_mymach_fleet_periodic_maintenance,group_mymach_fleet_manager,1,1,1,1
|
||||
access_mymach_fleet_fuel_index_user,mymach.fleet.fuel.index.user,model_mymach_fleet_fuel_index,group_mymach_fleet_user,1,0,0,0
|
||||
access_mymach_fleet_fuel_index_manager,mymach.fleet.fuel.index.manager,model_mymach_fleet_fuel_index,group_mymach_fleet_manager,1,1,1,1
|
||||
access_mymach_fleet_contract_user,contract_user,model_mymach_fleet_contract,mymach_fleet_intelligence.group_mymach_fleet_user,1,0,0,0
|
||||
access_mymach_fleet_contract_manager,contract_manager,model_mymach_fleet_contract,mymach_fleet_intelligence.group_mymach_fleet_manager,1,1,1,1
|
||||
access_mymach_fleet_maintenance_cost_manager,maintenance_cost_manager,model_mymach_fleet_maintenance_cost,mymach_fleet_intelligence.group_mymach_fleet_manager,1,1,1,1
|
||||
access_mymach_fleet_security_log_user,log_user,model_mymach_fleet_security_log,mymach_fleet_intelligence.group_mymach_fleet_user,1,1,0,0
|
||||
access_mymach_fleet_security_log_manager,log_manager,model_mymach_fleet_security_log,mymach_fleet_intelligence.group_mymach_fleet_manager,1,1,1,1
|
||||
access_mymach_fleet_route_wizard_user,route_wizard_user,model_mymach_fleet_route_exception_wizard,mymach_fleet_intelligence.group_mymach_fleet_user,1,1,1,1
|
||||
access_mymach_fleet_reservation_user,reservation_user,model_mymach_fleet_reservation,mymach_fleet_intelligence.group_mymach_fleet_user,1,1,1,0
|
||||
access_mymach_fleet_reservation_manager,reservation_manager,model_mymach_fleet_reservation,mymach_fleet_intelligence.group_mymach_fleet_manager,1,1,1,1
|
||||
access_mymach_fleet_home_user,home_user,model_mymach_fleet_home,mymach_fleet_intelligence.group_mymach_fleet_user,1,1,1,1
|
||||
access_mymach_fleet_fine_user,fine_user,model_mymach_fleet_fine,mymach_fleet_intelligence.group_mymach_fleet_user,1,0,0,0
|
||||
access_mymach_fleet_fine_manager,fine_manager,model_mymach_fleet_fine,mymach_fleet_intelligence.group_mymach_fleet_manager,1,1,1,1
|
||||
access_mymach_fleet_handover_user,handover_user,model_mymach_fleet_handover,mymach_fleet_intelligence.group_mymach_fleet_user,1,1,1,0
|
||||
access_mymach_fleet_handover_manager,handover_manager,model_mymach_fleet_handover,mymach_fleet_intelligence.group_mymach_fleet_manager,1,1,1,1
|
||||
access_mymach_fleet_periodic_maintenance_user,periodic_maintenance_user,model_mymach_fleet_periodic_maintenance,mymach_fleet_intelligence.group_mymach_fleet_user,1,1,0,0
|
||||
access_mymach_fleet_periodic_maintenance_manager,periodic_maintenance_manager,model_mymach_fleet_periodic_maintenance,mymach_fleet_intelligence.group_mymach_fleet_manager,1,1,1,1
|
||||
access_mymach_fleet_fuel_index_user,mymach.fleet.fuel.index.user,model_mymach_fleet_fuel_index,mymach_fleet_intelligence.group_mymach_fleet_user,1,0,0,0
|
||||
access_mymach_fleet_fuel_index_manager,mymach.fleet.fuel.index.manager,model_mymach_fleet_fuel_index,mymach_fleet_intelligence.group_mymach_fleet_manager,1,1,1,1
|
||||
|
||||
|
87
addons/mymach_fleet_intelligence/security/record_rules.xml
Normal file
87
addons/mymach_fleet_intelligence/security/record_rules.xml
Normal file
@@ -0,0 +1,87 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data noupdate="0">
|
||||
<!-- RECORD RULES (Sözleşme) -->
|
||||
<record id="rule_mymach_fleet_contract_user" model="ir.rule">
|
||||
<field name="name">Sürücüler kendi sözleşmesini görür</field>
|
||||
<field name="model_id" ref="model_mymach_fleet_contract"/>
|
||||
<field name="domain_force">[('driver_id', '=', user.partner_id.id)]</field>
|
||||
<field name="groups" eval="[(4, ref('group_mymach_fleet_user'))]"/>
|
||||
</record>
|
||||
<record id="rule_mymach_fleet_contract_manager" model="ir.rule">
|
||||
<field name="name">Yöneticiler tüm sözleşmeleri görür</field>
|
||||
<field name="model_id" ref="model_mymach_fleet_contract"/>
|
||||
<field name="domain_force">[(1, '=', 1)]</field>
|
||||
<field name="groups" eval="[(4, ref('group_mymach_fleet_manager'))]"/>
|
||||
</record>
|
||||
|
||||
<!-- RECORD RULES (Rezervasyon) -->
|
||||
<record id="rule_mymach_fleet_reservation_user" model="ir.rule">
|
||||
<field name="name">Sürücüler kendi taleplerini görür</field>
|
||||
<field name="model_id" ref="model_mymach_fleet_reservation"/>
|
||||
<field name="domain_force">[('create_uid', '=', user.id)]</field>
|
||||
<field name="groups" eval="[(4, ref('group_mymach_fleet_user'))]"/>
|
||||
</record>
|
||||
<record id="rule_mymach_fleet_reservation_manager" model="ir.rule">
|
||||
<field name="name">Yöneticiler tüm talepleri görür</field>
|
||||
<field name="model_id" ref="model_mymach_fleet_reservation"/>
|
||||
<field name="domain_force">[(1, '=', 1)]</field>
|
||||
<field name="groups" eval="[(4, ref('group_mymach_fleet_manager'))]"/>
|
||||
</record>
|
||||
|
||||
<!-- RECORD RULES (Teslimat / Handover) -->
|
||||
<record id="rule_mymach_fleet_handover_user" model="ir.rule">
|
||||
<field name="name">Sürücüler kendi teslimatlarını görür</field>
|
||||
<field name="model_id" ref="model_mymach_fleet_handover"/>
|
||||
<field name="domain_force">[('driver_id', '=', user.partner_id.id)]</field>
|
||||
<field name="groups" eval="[(4, ref('group_mymach_fleet_user'))]"/>
|
||||
</record>
|
||||
<record id="rule_mymach_fleet_handover_manager" model="ir.rule">
|
||||
<field name="name">Yöneticiler tüm teslimatları görür</field>
|
||||
<field name="model_id" ref="model_mymach_fleet_handover"/>
|
||||
<field name="domain_force">[(1, '=', 1)]</field>
|
||||
<field name="groups" eval="[(4, ref('group_mymach_fleet_manager'))]"/>
|
||||
</record>
|
||||
|
||||
<!-- RECORD RULES (Güvenlik / Rota Sapma Logları) -->
|
||||
<record id="rule_mymach_fleet_security_log_user" model="ir.rule">
|
||||
<field name="name">Sürücüler kendi rota sapma uyarılarını görür</field>
|
||||
<field name="model_id" ref="model_mymach_fleet_security_log"/>
|
||||
<field name="domain_force">[('vehicle_id.driver_id', '=', user.partner_id.id)]</field>
|
||||
<field name="groups" eval="[(4, ref('group_mymach_fleet_user'))]"/>
|
||||
</record>
|
||||
<record id="rule_mymach_fleet_security_log_manager" model="ir.rule">
|
||||
<field name="name">Yöneticiler tüm güvenlik ihlallerini görür</field>
|
||||
<field name="model_id" ref="model_mymach_fleet_security_log"/>
|
||||
<field name="domain_force">[(1, '=', 1)]</field>
|
||||
<field name="groups" eval="[(4, ref('group_mymach_fleet_manager'))]"/>
|
||||
</record>
|
||||
<!-- RECORD RULES (Cezalar ve Giderler) -->
|
||||
<record id="rule_mymach_fleet_fine_user" model="ir.rule">
|
||||
<field name="name">Sürücüler kendi cezalarını görür</field>
|
||||
<field name="model_id" ref="model_mymach_fleet_fine"/>
|
||||
<field name="domain_force">[('driver_id', '=', user.partner_id.id)]</field>
|
||||
<field name="groups" eval="[(4, ref('group_mymach_fleet_user'))]"/>
|
||||
</record>
|
||||
<record id="rule_mymach_fleet_fine_manager" model="ir.rule">
|
||||
<field name="name">Yöneticiler tüm cezaları görür</field>
|
||||
<field name="model_id" ref="model_mymach_fleet_fine"/>
|
||||
<field name="domain_force">[(1, '=', 1)]</field>
|
||||
<field name="groups" eval="[(4, ref('group_mymach_fleet_manager'))]"/>
|
||||
</record>
|
||||
|
||||
<!-- RECORD RULES (Periyodik Bakım) -->
|
||||
<record id="rule_mymach_fleet_periodic_maintenance_user" model="ir.rule">
|
||||
<field name="name">Sürücüler kendi araçlarının bakımlarını görür</field>
|
||||
<field name="model_id" ref="model_mymach_fleet_periodic_maintenance"/>
|
||||
<field name="domain_force">[('vehicle_id.driver_id', '=', user.partner_id.id)]</field>
|
||||
<field name="groups" eval="[(4, ref('group_mymach_fleet_user'))]"/>
|
||||
</record>
|
||||
<record id="rule_mymach_fleet_periodic_maintenance_manager" model="ir.rule">
|
||||
<field name="name">Yöneticiler tüm bakımları görür</field>
|
||||
<field name="model_id" ref="model_mymach_fleet_periodic_maintenance"/>
|
||||
<field name="domain_force">[(1, '=', 1)]</field>
|
||||
<field name="groups" eval="[(4, ref('group_mymach_fleet_manager'))]"/>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
@@ -10,91 +10,7 @@
|
||||
<!-- Yönetici (Admin) Grubu -->
|
||||
<record id="group_mymach_fleet_manager" model="res.groups">
|
||||
<field name="name">Yönetici / Admin (MyMach)</field>
|
||||
<field name="implied_ids" eval="[(4, ref('group_mymach_fleet_user'))]"/>
|
||||
<field name="user_ids" eval="[(4, ref('base.user_admin')), (4, ref('base.user_root'))]"/>
|
||||
</record>
|
||||
|
||||
<!-- RECORD RULES (Sözleşme) -->
|
||||
<record id="rule_mymach_fleet_contract_user" model="ir.rule">
|
||||
<field name="name">Sürücüler kendi sözleşmesini görür</field>
|
||||
<field name="model_id" ref="model_mymach_fleet_contract"/>
|
||||
<field name="domain_force">[('driver_id', '=', user.partner_id.id)]</field>
|
||||
<field name="groups" eval="[(4, ref('group_mymach_fleet_user'))]"/>
|
||||
</record>
|
||||
<record id="rule_mymach_fleet_contract_manager" model="ir.rule">
|
||||
<field name="name">Yöneticiler tüm sözleşmeleri görür</field>
|
||||
<field name="model_id" ref="model_mymach_fleet_contract"/>
|
||||
<field name="domain_force">[(1, '=', 1)]</field>
|
||||
<field name="groups" eval="[(4, ref('group_mymach_fleet_manager'))]"/>
|
||||
</record>
|
||||
|
||||
<!-- RECORD RULES (Rezervasyon) -->
|
||||
<record id="rule_mymach_fleet_reservation_user" model="ir.rule">
|
||||
<field name="name">Sürücüler kendi taleplerini görür</field>
|
||||
<field name="model_id" ref="model_mymach_fleet_reservation"/>
|
||||
<field name="domain_force">[('create_uid', '=', user.id)]</field>
|
||||
<field name="groups" eval="[(4, ref('group_mymach_fleet_user'))]"/>
|
||||
</record>
|
||||
<record id="rule_mymach_fleet_reservation_manager" model="ir.rule">
|
||||
<field name="name">Yöneticiler tüm talepleri görür</field>
|
||||
<field name="model_id" ref="model_mymach_fleet_reservation"/>
|
||||
<field name="domain_force">[(1, '=', 1)]</field>
|
||||
<field name="groups" eval="[(4, ref('group_mymach_fleet_manager'))]"/>
|
||||
</record>
|
||||
|
||||
<!-- RECORD RULES (Teslimat / Handover) -->
|
||||
<record id="rule_mymach_fleet_handover_user" model="ir.rule">
|
||||
<field name="name">Sürücüler kendi teslimatlarını görür</field>
|
||||
<field name="model_id" ref="model_mymach_fleet_handover"/>
|
||||
<field name="domain_force">[('driver_id', '=', user.partner_id.id)]</field>
|
||||
<field name="groups" eval="[(4, ref('group_mymach_fleet_user'))]"/>
|
||||
</record>
|
||||
<record id="rule_mymach_fleet_handover_manager" model="ir.rule">
|
||||
<field name="name">Yöneticiler tüm teslimatları görür</field>
|
||||
<field name="model_id" ref="model_mymach_fleet_handover"/>
|
||||
<field name="domain_force">[(1, '=', 1)]</field>
|
||||
<field name="groups" eval="[(4, ref('group_mymach_fleet_manager'))]"/>
|
||||
</record>
|
||||
|
||||
<!-- RECORD RULES (Güvenlik / Rota Sapma Logları) -->
|
||||
<record id="rule_mymach_fleet_security_log_user" model="ir.rule">
|
||||
<field name="name">Sürücüler kendi rota sapma uyarılarını görür</field>
|
||||
<field name="model_id" ref="model_mymach_fleet_security_log"/>
|
||||
<field name="domain_force">[('vehicle_id.driver_id', '=', user.partner_id.id)]</field>
|
||||
<field name="groups" eval="[(4, ref('group_mymach_fleet_user'))]"/>
|
||||
</record>
|
||||
<record id="rule_mymach_fleet_security_log_manager" model="ir.rule">
|
||||
<field name="name">Yöneticiler tüm güvenlik ihlallerini görür</field>
|
||||
<field name="model_id" ref="model_mymach_fleet_security_log"/>
|
||||
<field name="domain_force">[(1, '=', 1)]</field>
|
||||
<field name="groups" eval="[(4, ref('group_mymach_fleet_manager'))]"/>
|
||||
</record>
|
||||
<!-- RECORD RULES (Cezalar ve Giderler) -->
|
||||
<record id="rule_mymach_fleet_fine_user" model="ir.rule">
|
||||
<field name="name">Sürücüler kendi cezalarını görür</field>
|
||||
<field name="model_id" ref="model_mymach_fleet_fine"/>
|
||||
<field name="domain_force">[('driver_id', '=', user.partner_id.id)]</field>
|
||||
<field name="groups" eval="[(4, ref('group_mymach_fleet_user'))]"/>
|
||||
</record>
|
||||
<record id="rule_mymach_fleet_fine_manager" model="ir.rule">
|
||||
<field name="name">Yöneticiler tüm cezaları görür</field>
|
||||
<field name="model_id" ref="model_mymach_fleet_fine"/>
|
||||
<field name="domain_force">[(1, '=', 1)]</field>
|
||||
<field name="groups" eval="[(4, ref('group_mymach_fleet_manager'))]"/>
|
||||
</record>
|
||||
|
||||
<!-- RECORD RULES (Periyodik Bakım) -->
|
||||
<record id="rule_mymach_fleet_periodic_maintenance_user" model="ir.rule">
|
||||
<field name="name">Sürücüler kendi araçlarının bakımlarını görür</field>
|
||||
<field name="model_id" ref="model_mymach_fleet_periodic_maintenance"/>
|
||||
<field name="domain_force">[('vehicle_id.driver_id', '=', user.partner_id.id)]</field>
|
||||
<field name="groups" eval="[(4, ref('group_mymach_fleet_user'))]"/>
|
||||
</record>
|
||||
<record id="rule_mymach_fleet_periodic_maintenance_manager" model="ir.rule">
|
||||
<field name="name">Yöneticiler tüm bakımları görür</field>
|
||||
<field name="model_id" ref="model_mymach_fleet_periodic_maintenance"/>
|
||||
<field name="domain_force">[(1, '=', 1)]</field>
|
||||
<field name="groups" eval="[(4, ref('group_mymach_fleet_manager'))]"/>
|
||||
<field name="implied_ids" eval="[(4, ref('mymach_fleet_intelligence.group_mymach_fleet_user'))]"/>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
|
||||
@@ -82,7 +82,6 @@
|
||||
<!-- Ana Menü ve Alt Menüler -->
|
||||
<menuitem id="menu_mymach_fleet_intelligence_root"
|
||||
name="MyMach Filo Zekası"
|
||||
action="action_mymach_fleet_home_server"
|
||||
web_icon="fleet,static/description/icon.png"
|
||||
sequence="10"/>
|
||||
|
||||
|
||||
@@ -0,0 +1,282 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<template id="driver_tracker_template" name="MyMach Sürücü Mobil Takip">
|
||||
<t t-call="web.html_container">
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"/>
|
||||
<title>Şoför Konum Takibi</title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet"/>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"/>
|
||||
<style>
|
||||
body {
|
||||
background-color: #0f172a;
|
||||
color: #f8fafc;
|
||||
font-family: 'Inter', -apple-system, sans-serif;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
.header {
|
||||
background-color: #1e293b;
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
border-bottom: 1px solid #334155;
|
||||
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
.header h2 {
|
||||
margin: 0;
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
color: #e2e8f0;
|
||||
}
|
||||
.main-container {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 20px;
|
||||
}
|
||||
.vehicle-selector {
|
||||
width: 100%;
|
||||
max-width: 350px;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
.form-select {
|
||||
background-color: #1e293b;
|
||||
color: #f8fafc;
|
||||
border: 1px solid #475569;
|
||||
border-radius: 12px;
|
||||
padding: 15px;
|
||||
font-size: 16px;
|
||||
box-shadow: inset 0 2px 4px 0 rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
.form-select:focus {
|
||||
background-color: #1e293b;
|
||||
color: white;
|
||||
border-color: #3b82f6;
|
||||
box-shadow: 0 0 0 0.25rem rgba(59, 130, 246, 0.25);
|
||||
}
|
||||
.btn-track {
|
||||
width: 220px;
|
||||
height: 220px;
|
||||
border-radius: 50%;
|
||||
font-size: 24px;
|
||||
font-weight: 700;
|
||||
border: none;
|
||||
color: white;
|
||||
background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%);
|
||||
box-shadow: 0 10px 25px -5px rgba(59, 130, 246, 0.5), inset 0 4px 6px -1px rgba(255, 255, 255, 0.2);
|
||||
transition: all 0.3s ease;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 15px;
|
||||
}
|
||||
.btn-track:active {
|
||||
transform: scale(0.95);
|
||||
}
|
||||
.btn-track.active {
|
||||
background: linear-gradient(135deg, #ef4444 0%, #dc2626 100%);
|
||||
box-shadow: 0 10px 25px -5px rgba(239, 68, 68, 0.5), inset 0 4px 6px -1px rgba(255, 255, 255, 0.2);
|
||||
animation: pulse-red 2s infinite;
|
||||
}
|
||||
@keyframes pulse-red {
|
||||
0% { box-shadow: 0 0 0 0 rgba(239, 68, 68, 0.7); }
|
||||
70% { box-shadow: 0 0 0 20px rgba(239, 68, 68, 0); }
|
||||
100% { box-shadow: 0 0 0 0 rgba(239, 68, 68, 0); }
|
||||
}
|
||||
.btn-track i {
|
||||
font-size: 50px;
|
||||
}
|
||||
.status-panel {
|
||||
margin-top: 40px;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
max-width: 350px;
|
||||
background-color: #1e293b;
|
||||
padding: 15px;
|
||||
border-radius: 12px;
|
||||
border: 1px solid #334155;
|
||||
}
|
||||
.status-text {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
color: #94a3b8;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
.coords-text {
|
||||
font-size: 14px;
|
||||
color: #cbd5e1;
|
||||
font-family: monospace;
|
||||
}
|
||||
.last-ping {
|
||||
font-size: 12px;
|
||||
color: #10b981;
|
||||
margin-top: 10px;
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="header">
|
||||
<h2><i class="fa-solid fa-truck-fast"></i> Sürücü Konum Paneli</h2>
|
||||
</div>
|
||||
|
||||
<div class="main-container">
|
||||
<div class="vehicle-selector">
|
||||
<label class="form-label" style="color: #94a3b8; font-size: 14px; font-weight: 500; margin-bottom: 8px;">Kullanılan Araç:</label>
|
||||
<select id="vehicle_select" class="form-select">
|
||||
<t t-foreach="vehicles" t-as="v">
|
||||
<option t-att-value="v.id"><t t-esc="v.license_plate"/> <t t-if="v.name">- <t t-esc="v.name"/></t></option>
|
||||
</t>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<button id="toggleTrackBtn" class="btn-track">
|
||||
<i class="fa-solid fa-location-crosshairs" id="trackIcon"></i>
|
||||
<span id="trackLabel">SEFERE BAŞLA</span>
|
||||
</button>
|
||||
|
||||
<div class="status-panel">
|
||||
<div class="status-text" id="statusText">Konum takibi kapalı.</div>
|
||||
<div class="coords-text" id="coordsText">-- / --</div>
|
||||
<div class="last-ping" id="lastPingText"><i class="fa-solid fa-check-circle"></i> Son Gönderim: <span></span></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
const btn = document.getElementById('toggleTrackBtn');
|
||||
const trackLabel = document.getElementById('trackLabel');
|
||||
const trackIcon = document.getElementById('trackIcon');
|
||||
const statusText = document.getElementById('statusText');
|
||||
const coordsText = document.getElementById('coordsText');
|
||||
const lastPingText = document.getElementById('lastPingText');
|
||||
const lastPingSpan = lastPingText.querySelector('span');
|
||||
const vehicleSelect = document.getElementById('vehicle_select');
|
||||
|
||||
let isTracking = false;
|
||||
let watchId = null;
|
||||
const API_TOKEN = 'MYMACH_SECURE_TOKEN_2026';
|
||||
|
||||
function formatTime(date) {
|
||||
return date.toLocaleTimeString('tr-TR', { hour: '2-digit', minute: '2-digit', second: '2-digit' });
|
||||
}
|
||||
|
||||
function sendPing(lat, lng) {
|
||||
const vehicleId = parseInt(vehicleSelect.value);
|
||||
if (!vehicleId) return;
|
||||
|
||||
const payload = {
|
||||
jsonrpc: "2.0",
|
||||
method: "call",
|
||||
params: {
|
||||
vehicle_id: vehicleId,
|
||||
latitude: lat,
|
||||
longitude: lng,
|
||||
api_token: API_TOKEN
|
||||
}
|
||||
};
|
||||
|
||||
fetch('/mymach/fleet/ping', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(payload)
|
||||
}).then(res => res.json())
|
||||
.then(data => {
|
||||
console.log('Ping Success:', data);
|
||||
lastPingText.style.display = 'block';
|
||||
lastPingSpan.textContent = formatTime(new Date());
|
||||
}).catch(err => {
|
||||
console.error('Ping Error:', err);
|
||||
});
|
||||
}
|
||||
|
||||
function successPosition(position) {
|
||||
const lat = position.coords.latitude;
|
||||
const lng = position.coords.longitude;
|
||||
coordsText.textContent = lat.toFixed(6) + " / " + lng.toFixed(6);
|
||||
sendPing(lat, lng);
|
||||
}
|
||||
|
||||
function errorPosition(err) {
|
||||
console.warn(`ERROR(${err.code}): ${err.message}`);
|
||||
statusText.textContent = "Hata: Konum alınamadı!";
|
||||
statusText.style.color = "#ef4444";
|
||||
stopTracking();
|
||||
}
|
||||
|
||||
function startTracking() {
|
||||
if (!navigator.geolocation) {
|
||||
alert("Tarayıcınız konum servisini desteklemiyor.");
|
||||
return;
|
||||
}
|
||||
|
||||
isTracking = true;
|
||||
btn.classList.add('active');
|
||||
trackLabel.textContent = "SEFERİ BİTİR";
|
||||
trackIcon.className = "fa-solid fa-stop";
|
||||
statusText.textContent = "Konum canlı takip ediliyor...";
|
||||
statusText.style.color = "#10b981";
|
||||
vehicleSelect.disabled = true;
|
||||
|
||||
// watchPosition keeps getting location updates
|
||||
watchId = navigator.geolocation.watchPosition(successPosition, errorPosition, {
|
||||
enableHighAccuracy: true,
|
||||
timeout: 10000,
|
||||
maximumAge: 0
|
||||
});
|
||||
}
|
||||
|
||||
function stopTracking() {
|
||||
isTracking = false;
|
||||
btn.classList.remove('active');
|
||||
trackLabel.textContent = "SEFERE BAŞLA";
|
||||
trackIcon.className = "fa-solid fa-location-crosshairs";
|
||||
statusText.textContent = "Konum takibi durduruldu.";
|
||||
statusText.style.color = "#94a3b8";
|
||||
vehicleSelect.disabled = false;
|
||||
lastPingText.style.display = 'none';
|
||||
|
||||
if (watchId !== null) {
|
||||
navigator.geolocation.clearWatch(watchId);
|
||||
watchId = null;
|
||||
}
|
||||
}
|
||||
|
||||
btn.addEventListener('click', function() {
|
||||
if (isTracking) {
|
||||
stopTracking();
|
||||
} else {
|
||||
startTracking();
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
</t>
|
||||
</template>
|
||||
|
||||
<!-- Odoo Menüsü İçin URL Aksiyonu ve Menü Öğesi -->
|
||||
<record id="action_mymach_driver_tracker_url" model="ir.actions.act_url">
|
||||
<field name="name">Sürücü Mobil Takip Ekranı</field>
|
||||
<field name="url">/mymach/driver/tracker</field>
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
|
||||
<menuitem id="menu_mymach_driver_tracker"
|
||||
name="Sürücü Mobil Takip"
|
||||
parent="hr.menu_hr_root"
|
||||
action="action_mymach_driver_tracker_url"
|
||||
sequence="15"/>
|
||||
</odoo>
|
||||
|
||||
@@ -25,6 +25,12 @@
|
||||
<field name="is_maintenance_critical" invisible="1"/>
|
||||
<widget name="web_ribbon" title="SATMAK DAHA KARLI!" bg_color="bg-danger" invisible="not is_maintenance_critical"/>
|
||||
</xpath>
|
||||
|
||||
<!-- Faz 2.3 ve 2.6: Araç Türü ve Şirket Lokasyonu (Standart Text Location Yerine) -->
|
||||
<xpath expr="//field[@name='location']" position="replace">
|
||||
<field name="mymach_vehicle_type" />
|
||||
<field name="mymach_location_id" />
|
||||
</xpath>
|
||||
<xpath expr="//notebook" position="inside">
|
||||
<page string="Finans & Gider Analizi (KM / Aylık / Yıllık)">
|
||||
<group string="Para Birimi & Listbox Gösterim Ayarları">
|
||||
|
||||
@@ -60,12 +60,7 @@ action = {
|
||||
<!-- Floating Content Wrapper -->
|
||||
<div class="mymach_zara_content" style="position: relative;">
|
||||
|
||||
<!-- Dil Seçici (Top Right) -->
|
||||
<div style="position: absolute; top: 10px; right: 15px; width: 140px; z-index: 100;">
|
||||
<field name="dashboard_lang_id" widget="selection" style="background: rgba(15, 23, 42, 0.6) !important; color: white !important; border: 1px solid rgba(255, 255, 255, 0.15) !important; border-radius: 6px; padding: 4px; width: 100%; display: block; margin-bottom: 5px;"/>
|
||||
<button name="action_apply_language" type="object" string="🌐 Dili Değiştir" class="btn btn-sm btn-outline-light" style="width: 100%; font-size: 11px; padding: 3px;"/>
|
||||
</div>
|
||||
|
||||
<!-- Dil Seçici Kaldırıldı (Odoo Standardı Kullanılacak) -->
|
||||
<!-- Zara-Style Minimalist Editorial Header -->
|
||||
<div style="text-align: center; margin-bottom: 10px; border-bottom: 1px solid rgba(255,255,255,0.08); padding-bottom: 25px;">
|
||||
<h1 class="mymach_zara_title" style="color: #ffffff !important; text-shadow: 0 0 15px rgba(255, 255, 255, 0.5); font-weight: 800;">MYMACH FLEET INTELLIGENCE</h1>
|
||||
@@ -216,7 +211,14 @@ action = {
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Odoo'nun Cache sorunlarını aşmak için Root Menu yerine Alt Menü (Sequence 0) ekliyoruz -->
|
||||
<!-- Root Menüye Ana Pano Aksiyonunu Bağlıyoruz -->
|
||||
<menuitem id="menu_mymach_fleet_intelligence_root"
|
||||
name="MyMach Filo Zekası"
|
||||
action="action_mymach_fleet_home_server"
|
||||
web_icon="fleet,static/description/icon.png"
|
||||
sequence="10"/>
|
||||
|
||||
<!-- Alt Menü: Ana Pano -->
|
||||
<menuitem id="menu_mymach_fleet_home"
|
||||
name="Ana Pano"
|
||||
parent="menu_mymach_fleet_intelligence_root"
|
||||
|
||||
15
addons/mymach_fleet_intelligence/views/res_users_views.xml
Normal file
15
addons/mymach_fleet_intelligence/views/res_users_views.xml
Normal file
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<record id="view_users_form_mymach_inherit" model="ir.ui.view">
|
||||
<field name="name">res.users.form.mymach.inherit</field>
|
||||
<field name="model">res.users</field>
|
||||
<field name="inherit_id" ref="base.view_users_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//notebook/page[@name='access_rights']//group[1]" position="inside">
|
||||
<group string="MYMACH FİLO">
|
||||
<field name="mymach_role"/>
|
||||
</group>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
Reference in New Issue
Block a user