Odoo-da paketlər satan, məsələn, aksesuarlar və quraşdırma ilə birlikdə ölçü cihazı, avadanlıq və qurulma ilə iş yeri və ya bir neçə xidmətdən ibarət texniki xidmət paketi təqdim edən hər kəsin təklifdə eyni anda iki şeyə ehtiyacı var: Tərkib sifarişdə yer almalıdır ki, anbar, texniki heyət və fakturalaşdırma nəyin təhvil veriləcəyini bilsin. Lakin müştəri üçün çap versiyasında hər halda hər bir ayrı mövqe hər bir ayrı qiymətlə görünməməlidir.
OCA modulu sale_product_set məhsul dəstlərini (satış üçün spesifikasiyaları) bir kliklə təklifə əlavə etməyə imkan verir. Çap görünüşünü isə o müəyyən etmir. Bunun üçün biz Sale Product Set Layout modulunu (sale_product_set_layout) hazırladıq. O, Odoo 19 üçün yazılıb və AGPL-3 lisenziyası altında sərbəst proqram təminatı kimi GitHub-da pulsuz təqdim olunur:
github.com/Alex0176/odoo-sale-product-set-layout
Bu yazının məzmunu
- Problem: çap görünüşünə təsiri olmayan məhsul dəstləri
- Modul nə edir
- Üç çap rejiminin təfərrüatları
- Gizlədilmiş sətirlər və sabit qiymət
- Texniki həyata keçirilmə
- İstənilməyən yan təsirlər olmadan quraşdırma
- Addım-addım istifadə
- Testlər
- Məhdudiyyətlər və hüquqi qeyd
- Tez-tez verilən suallar
- Biricon IT Services dəstəyi
Problem: çap görünüşünə təsiri olmayan məhsul dəstləri
Odoo-da məhsul dəsti miqdarları ilə birlikdə məhsulların əvvəlcədən hazırlanmış siyahısıdır. On məhsulu tək-tək axtarmaq əvəzinə, təklifdə Dəst əlavə et seçilir və bütün sətirlər bir anda əldə olunur. Bu, vaxta qənaət edir və unudulmuş mövqelərin qarşısını alır. sale_product_set modulu məhz bunu edir. Repozitoriya: OCA/sale-workflow dəstlərin özü isə product_set modulundan gəlir. Repozitoriya: OCA/product-attribute.
Təcrübədə üç boşluq qalır:
- Tanına bilən qruplaşdırma yoxdur. Dəst sətirləri təklifdə ayrı-ayrı mövqelər kimi yerləşir. Əlavə etdikdən sonra hansı sətirlərin bir yerə aid olduğu görünmür və dəstin ümumi məbləği heç yerdə göstərilmir.
- Çapa təsir yoxdur. Bəzən müştəri hər mövqeyi qiymətlə görməlidir, bəzən yalnız paket qiymətini, bəzən isə yalnız bir sətri. Bu, hər təklif üçün əl ilə deyil, hər dəst və ya hər müştəri üçün verilən qərardır.
- Qiymət düzəlişləri xoşagəlməzdir. Paketin qiymət siyahısındakı məbləğlərin cəmindən fərqlənən sabit qiyməti olmalıdırsa, düzəliş sətri lazım olur. O, hesablamaya aiddir, lakin mütləq müştərinin kağızında olmalı deyil.
Odoo 19 bunu səliqəli həll etmək üçün lazımi elementləri özü ilə gətirir: bölmələr və alt bölmələr – təklif sətirlərində Qiymətləri gizlət və Tərkibi gizlət seçimləri ilə (collapse_prices və collapse_composition sahələri). Modul özünəməxsus çap formatı icad etmək əvəzinə məhsul dəstini bu standart seçimlərlə birləşdirir.
Modul nə edir
- Dəstin bölmə kimi əlavə edilməsi. Dəst əlavə et köməkçisi dəstin adı ilə bölmə sətri yaradır, məsələn, 2 × Messkit Standard, və dəst sətirlərini onun altına yerləşdirir. Dəstin daxilindəki bölmələr alt bölmələrə çevrilir.
- Hər dəst üçün çap rejimi. Dəstdə onun necə çap ediləcəyi bir dəfə müəyyən edilir. Əlavə edərkən köməkçidə rejimi həmin bir hal üçün dəyişmək olar.
- Sətirlərin gizlədilməsi. Ayrı-ayrı sətirlər Çap etmə (dəstdə: Gizli) kimi işarələnə bilər. Onlar cəmə daxil olur, lakin nə çap olunur, nə də müştəri portalında göstərilir. Bu işarə təklifdən qaiməyə keçir.
- Hər dəst sətri üçün sabit qiymət. Dəst sətri qiymət siyahısındakı qiyməti əvəz edən sabit vahid qiymət daşıya bilər, məsələn, gizlədilmiş qiymət düzəlişi üçün.
Modulsuz (yalnız sale_product_set) | sale_product_set_layout ilə |
|---|---|
| Dəst sətirləri ayrı-ayrı mövqelər kimi | Dəstin adı ilə bölmə sətri, miqdar adda, sətirlər altında |
| Dəstdəki bölmələr bölmə olaraq qalır və strukturu pozur | Dəstdəki bölmələr alt bölmələrə çevrilir (line_subsection) |
| Çap görünüşü həmişə eynidir | Hər dəst üçün çap rejimi, əlavə edərkən dəyişdirilə bilər |
| Qiymət düzəlişi təklifdə və qaimədə görünür | Sətir gizlədilə bilər, lakin cəmə daxil olur |
| Qiymət yalnız qiymət siyahısından | İstəyə görə hər dəst sətri üçün sabit qiymət |
| Görünüş təklifdə bitir | Görünüş və gizlətmə təklif, sifariş, qaimə və müştəri portalı üçün keçərlidir |
Üç çap rejiminin təfərrüatları
Çap rejimi məhsul dəstindəki print_mode seçim sahəsidir. Əlavə edərkən o, bölmə sətrinin iki standart açarına çevrilir. Bunun üçün modulda yeganə, asan oxunan uyğunluq cədvəli var:
# Druckmodus -> (collapse_prices, collapse_composition) der Abschnittszeile
PRINT_MODE_FLAGS = {
"detailed": (False, False),
"total_only": (True, False),
"summary": (False, True),
}
Rejim (print_mode) | Dəstdə göstərilmə | Odoo-da standart seçim | Çap görünüşü |
|---|---|---|---|
detailed | Hər sətir qiymətlə | yoxdur | Bölmə, bütün sətirlər məbləğlə |
total_only | Qiymətsiz sətirlər, yalnız dəst cəmi | collapse_prices (Qiymətləri gizlət) | Cəmi olan bölmə, sətirlər yalnız adı və miqdarı ilə |
summary | Dəst cəmi ilə yalnız bir sətir | collapse_composition (Tərkibi gizlət) | Yalnız cəmi olan bölmə sətri |
Modul özünəməxsus çap formatı deyil, Odoo 19-un standart seçimlərindən istifadə etdiyinə görə təklif, sifariş təsdiqi, qaimə və müştəri portalı uyğunlaşdırılmış hesabat şablonları olmadan işləyir. Bölmə seçimlərini nəzərə alan öz hesabat şablonları olanlar da eyni davranışı əldə edir.
Gizlədilmiş sətirlər və sabit qiymət
Tez-tez rast gəlinən hal: paketin qiyməti ayrı-ayrı qiymətlərin cəmindən aşağıdır. Ayrı-ayrı qiymətləri əymək əvəzinə sabit qiymətli düzəliş sətri götürülür (məsələn, hər dəst üçün −50,00 €) və gizlədilir. Backend-də qaimə izlənilə bilən olur, çap versiyasında isə paket qiyməti görünür.
Başa düşmək üçün vacibdir: hide_in_report işarəsi hesablamada heç nəyi dəyişmir. Miqdar, qiymət, endirim, vergi, cəmlər və mühasibat yazıları dəyişmədən standart Odoo tərəfindən yaranır. Sətir yalnız çap versiyasında və portalda olmur.
- Məhsul dəstində: Gizli və istəyə görə Sabit qiymət ilə birlikdə Vahid qiymət olan dəst sətri.
- Təklif və qaimə sətirlərində: Çap etmə sütunu (
hide_in_report), dəstsiz adi sətirlər üçün də. - Ötürülmə: Sifarişdən qaimə yaradılarkən işarə qaimə sətrinə ötürülür. Təklif kopyalananda isə qalır.
Texniki həyata keçirilmə
Modul qəsdən kiçikdir: o, mövcud modelləri genişləndirir və yalnız Odoo-nun hansı sətirlərin çap ediləcəyinə və dəstin necə əlavə ediləcəyinə qərar verdiyi yerləri üzərinə yazır. Yeni hesabat şablonları, yeni modellər və SQL müdaxilələri yoxdur.
Genişləndirilmiş modellər və sahələr
| Model | Əlavə |
|---|---|
product.set | insert_as_section (Boolean, standart olaraq aktiv) və print_mode (seçim, məcburi sahə, standart detailed) sahələri |
product.set.line | hide_in_report, fixed_price, price_unit sahələri; prepare_sale_order_line_values() onları təklif sətrinə ötürür |
sale.product.set.wizard | insert_as_section, section_name, print_mode sahələri; _prepare_order_lines() bölmə sətrini qurur |
sale.order / sale.order.line | hide_in_report sahəsi (copy=True ilə); _get_order_lines_to_report() gizlədilmiş sətirləri keçir; _prepare_invoice_line() işarəni ötürür |
account.move / account.move.line | hide_in_report sahəsi; _get_move_lines_to_report(), _get_detailed_lines() və _get_subsection_lines() gizlədilmiş sətirləri süzgəcdən keçirir; _get_aml_vals() işarəni hesabat məlumatlarına daşıyır |
Təklifdə gizlətmə
Odoo 19 çap ediləcək təklif sətirlərini _get_order_lines_to_report() metodunda müəyyən edir. Modul orada süzgəc əlavə edir. Hesabat şablonuna müdaxilə lazım deyil: həm təklifin hesabat şablonu (sale/report/ir_actions_report_templates.xml), həm də portal şablonu (sale/views/sale_portal_templates.xml) bu metodu çağırır:
class SaleOrder(models.Model):
_inherit = "sale.order"
def _get_order_lines_to_report(self):
return super()._get_order_lines_to_report().filtered(
lambda line: not line.hide_in_report
)
Qaiməyə ötürülmə
Qaimə sətri təklif sətrindən yaradılarkən (_prepare_invoice_line()) işarə kopyalanır. Qaimə tərəfində Odoo 19-da sətirlərin hesabata düşməsinin bir neçə yolu var: əsas siyahı, bölmənin sətirləri və alt bölmənin sətirləri. Buna görə modul bir neçə yerdə süzgəc tətbiq edir (sənəddə _get_move_lines_to_report(), sətirdə isə _get_detailed_lines() və _get_subsection_lines()), əks halda gizlədilmiş sətir digər yollardan biri ilə yenidən peyda ola bilər:
class AccountMoveLine(models.Model):
_inherit = "account.move.line"
hide_in_report = fields.Boolean(string="Hidden in report")
def _get_aml_vals(self, hide_taxes):
res = super()._get_aml_vals(hide_taxes)
res["hide_in_report"] = self.hide_in_report
return res
def _get_detailed_lines(self, children_lines, direct_children_lines, subsection_lines):
res = super()._get_detailed_lines(children_lines, direct_children_lines, subsection_lines)
return [vals for vals in res if not vals.get("hide_in_report")]
def _get_subsection_lines(self, subsection_line, children_lines):
res = super()._get_subsection_lines(subsection_line, children_lines)
return [vals for vals in res if not vals.get("hide_in_report")]
Köməkçi: ayrı-ayrı sətirlər əvəzinə bölmə
sale_product_set-dən olan sale.product.set.wizard köməkçisi təklif sətirlərini _prepare_order_lines() metodunda yaradır. Modul bu metodu üzərinə yazır. Bölmə kimi əlavə et söndürülübsə, o, sadəcə ilkin metodu çağırır, davranış OCA modulundakı kimi qalır. Əks halda əvvəlcə iki standart açarı olan bölmə sətri yaranır, ardınca dəst sətirləri gəlir. Dəstin daxilindəki bölmələr alt bölmələrə çevrilir ki, əsas strukturu pozmasınlar:
def _prepare_order_lines(self):
if not self.insert_as_section:
return super()._prepare_order_lines()
sequence = self._get_max_sequence() + 1
collapse_prices, collapse_composition = PRINT_MODE_FLAGS[self.print_mode or "detailed"]
order_lines = [Command.create({
"display_type": "line_section",
"name": self.section_name or self.product_set_id.name,
"sequence": sequence,
"collapse_prices": collapse_prices,
"collapse_composition": collapse_composition,
})]
for set_line in self._get_lines():
sequence += 1
values = set_line.prepare_sale_order_line_values(self.order_id, self.quantity, sequence)
if values.get("display_type") == "line_section":
values["display_type"] = "line_subsection"
order_lines.append(Command.create(values))
return order_lines
Görünməyən qərarlar
- Köməkçidə ayrı hesablama metodları. Bölmə adı, çap rejimi və Bölmə kimi əlavə et üçün hər birinin öz
computemetodu var (store=True,readonly=False). Üçünün hamısında eyni metod olsaydı, bir sahə üçün açıq şəkildə ötürülmüş dəyər digərlərini sıfırlayardı. Bu, əsasən köməkçi koddan və ya testlərdən dəyərlərlə yaradılanda nəzərə çarpır. - Miqdarlı bölmə adı. Miqdar 1-ə bərabər olmadıqda adda yazılır (2 × Messkit Standard, onluq ayırıcı olaraq vergüllə), beləliklə çap versiyasında iki dəstin olduğu, miqdarı ikiqat olan bir dəstin olmadığı bilinir.
- Sabit qiymət yalnız məhsul sətirlərində.
prepare_sale_order_line_values()hide_in_reportvəprice_unit-i yalnız dəst sətri bölmə və ya qeyd sətri olmadıqda təyin edir. - Özümüz yazmaq əvəzinə standart Odoo. Çap rejimi və gizlətmə Odoo 19-un mövcud hook-larından və sahələrindən istifadə edir. Bu, yeniləmələri idarə oluna bilən edir: Odoo hesabat şablonunu dəyişsə, metodlar qaldığı müddətcə modul etibarlı qalır.
İstənilməyən yan təsirlər olmadan quraşdırma
İlkin şərtlər: Odoo 19.0, sale_product_set (OCA/sale-workflow, 19.0 branch-ı) və product_set (OCA/product-attribute, 19.0 branch-ı). Modulun özü sale_management, sale_product_set və account modullarından asılıdır.
OCA modullarında auto_install tələsi. Bir çox OCA repozitoriyasında auto_install olan modullar var. Onların asılılıqları mövcud olan kimi Odoo növbəti quraşdırma və ya yeniləmə zamanı onları soruşmadan birgə quraşdırır. Buna görə bütün OCA repozitoriyasını istehsal instansiyasının addons_path-inə qoyan hər kəs, ehtimal ki, heç kimin istəmədiyi modullar əldə edir. OCA/product-attribute üçün bu, məsələn, purchase_product_template_tags modulunə aiddir. Bizim yanaşmamız:
- İki OCA repozitoriyasını dayaz klonlayın (
git clone --depth 1 --branch 19.0). - Ayrıca qovluqda yalnız lazım olan iki modulu symlink ilə bağlayın və bütün repozitoriyaları deyil, məhz bu qovluğu
addons_path-ə daxil edin. - Test verilənlər bazasında quraşdırın və bu zaman hansı modulların quraşdırılmış statusu aldığını yoxlayın.
- Yalnız bundan sonra istehsalda quraşdırın,
--workers=0ilə, belə ki, çağırış HTTP portu uğrunda işləyən xidmətlə rəqabət aparmasın.
odoo-bin -c /etc/odoo/odoo.conf -d <datenbank> -i sale_product_set_layout --stop-after-init
Yeni sahələr və görünüşlər quraşdırıldıqdan sonra verilənlər bazasındadır. Xidmət çoxprosesli rejimdə işləyirsə, worker-lər dəyişdirilmiş registry-ni verilənlər bazası siqnalı vasitəsilə yenidən yükləyir. Modulun Python fayllarındakı dəyişikliklər isə yalnız xidmət yenidən başladıqdan sonra qüvvəyə minir.
Addım-addım istifadə
- Dəstin yaradılması: Satış → Məhsullar → Məhsul dəstləri. Dəstə ad verin, Bölmə kimi əlavə et və Çap rejimi seçin, məhsulları miqdarları ilə daxil edin. Düzəliş sətirlərinə Gizli və Sabit qiymət təyin edin.
- Təklifdə: Dəst əlavə et üzərinə klikləyin, dəsti və miqdarı seçin. Bölmə adı və çap rejimi əlavə etməzdən əvvəl dəyişdirilə bilər.
- Ayrı-ayrı sətirlərin gizlədilməsi: Təklifdə və ya qaimədə Çap etmə sütununu aktivləşdirin.
- Yoxlama: Önbaxışı və ya PDF-i açın. Müştərilər portalda eyni təsviri görür.
Testlər
Modul altı avtomatlaşdırılmış test təqdim edir, onları istehsala keçməzdən əvvəl test verilənlər bazasına qarşı icra edirik:
- Bölmə kimi əlavə etmə, çap rejimi və alt bölmə daxil olmaqla
- Gizlədilmiş sətir çap ediləcək sətirlərdə yoxdur
- Bir sətir rejimi (
summary) - Bölməsiz əlavə etmə, ilkin davranış
- Qaimə
hide_in_reportişarəsini qəbul edir, sətir_get_move_lines_to_report()-də yoxdur, bölmə cəmi isə onu yenə də ehtiva edir - Yalnız ümumi qiymət rejimində qaimə gizli sətri bölmə sətirlərində göstərmir, bölmə cəmi isə tam qalır
odoo-bin -d <testdatenbank> -i sale_product_set_layout \
--test-enable --test-tags=/sale_product_set_layout --stop-after-init
Alman dilində tərcümə i18n/de.po faylındadır.
Məhdudiyyətlər və hüquqi qeyd
- Yalnız görünüş. Modul Odoo-nun qiymətləri, endirimləri və vergiləri necə hesablamasını dəyişmir. O, yalnız nəyin çap edildiyini və portalda göstərildiyini dəyişir.
- Gizlədilmiş sətirlər backend-də görünür. İşarə çapa və portala aiddir, əməkdaşların ekran görünüşünə yox.
- Qaimə məlumatlarını yoxlayın. Gizlədilmiş sətirlər cəmə daxil olur, lakin sənəddə yer almır. Bunun ölkənizdə qaimələrə qoyulan tələblərlə, məsələn, çatdırılmış əşyaların və ya göstərilmiş xidmətlərin məcburi təsviri ilə uyğun olub-olmadığını qaimələrdə istifadədən əvvəl vergi məsləhətçinizlə dəqiqləşdirməlisiniz. Təkliflərdə gizlətmə daha problemsizdir. Bu yazı hüquqi məsləhət deyil.
- Odoo 19 üçün sınaqdan keçirilib. Modulu Odoo 19.0 Community üçün hazırlamış və sınaqdan keçirmişik. O, Odoo 19-da bu formada mövcud olan bölmə seçimlərindən istifadə edir. Digər versiyalar üçün yoxlamamışıq.
Tez-tez verilən suallar
Odoo 19 artıq bölmələri bacarırsa, mənə modul nə üçün lazımdır?
Bölmə seçimləri Odoo-nun özündə var. Çatışmayan məhsul dəsti ilə əlaqə idi: dəst dəstdə saxlanılmış çap rejimi ilə avtomatik olaraq bölmə kimi əlavə edilməli idi. Modul olmadan hər əlavə etmədən sonra bölmə sətrini əl ilə yaratmaq və konfiqurasiya etmək lazımdır.
“Qiymətləri gizlət” və “Tərkibi gizlət” bir-birindən nə ilə fərqlənir?
“Qiymətləri gizlət” (collapse_prices) sətirləri saxlayır, lakin məbləğləri göstərmir, yalnız bölmədəki cəmi göstərir. “Tərkibi gizlət” (collapse_composition) sətirləri tamamilə gizlədir, müştəri yalnız cəmi olan bölməni görür.
Gizlədilmiş sətir qaimə cəminə daxil olurmu?
Bəli. Gizlədilmiş sətirlər cəmdə, vergidə və mühasibat yazısında qalır. İşarə yalnız çap versiyasında və müştəri portalında təsvirə aiddir.
Əlavə edərkən çap rejimini hələ də dəyişə bilərəmmi?
Bəli. Rejim dəstdən ilkin dəyər kimi gəlir, köməkçidə isə həmin əlavə etmə üçün dəyişdirilə bilər. Dəstin özü bu zaman dəyişməz qalır.
Bölmə kimi əlavə et seçimini söndürsəm nə baş verir?
Onda köməkçi OCA modulu sale_product_set-dəki kimi davranır: dəst sətirləri bölməsiz əlavə edilir.
Modul gözlənilmədən başqa modullar quraşdırırmı?
Modulun özü yox. Lakin bütün repozitoriyaları addons_path-ə qoyduqda OCA repozitoriyalarında auto_install modulları ola bilər. Buna görə yalnız lazım olan iki modulu bağlayın (Quraşdırma bölməsinə baxın).
Modul Odoo Enterprise ilə işləyirmi?
Modul yalnız Community modullarından (sale_management, account) və iki OCA modulundan asılıdır. Biz onu Odoo 19 Community-də istifadə edirik. Enterprise-da sınaqdan keçirməmişik.
Modul hansı lisenziya altındadır?
AGPL-3 altında. Dəyişikliklər eyni lisenziya altında qaldıqca ondan istifadə edə, onu uyğunlaşdıra və yaya bilərsiniz. Xətalar və təkmilləşdirmə təklifləri Issue kimi GitHub repozitoriyası üzərində məmnuniyyətlə qəbul edilir.
Biricon IT Services dəstəyi
Biz kiçik və orta müəssisələr üçün Odoo quraşdırmalarına xidmət göstəririk: tətbiqdən uyğunlaşdırmalara və miqrasiyalara, cari istismara qədər. Odoo 19-da məhsul dəstlərini, təklif şablonlarını və ya hesabatları iş proseslərinizə uyğunlaşdırmaq istəyirsinizsə və ya bu kimi bir modulu yoxlayıb istehsal instansiyanıza təhlükəsiz gətirmək istəyirsinizsə, sizə məmnuniyyətlə dəstək oluruq. Digər öz hazırlıqlarımızı bloqumuzda tapa bilərsiniz, məsələn, Qaralama qaimələrin birləşdirilməsi və Bank ödənişlərinin qaimələrə avtomatik uyğunlaşdırılması.
Vəziyyət: 2 noyabr 2026. Modul versiyası 19.0.1.0.0. Təsvirlərdəki nümunə məlumatlar sərbəst seçilib, məbləğlər netto.