Kas Odoo pārdod komplektus, piemēram, mērierīci ar piederumiem un montāžu, darbavietu ar aparatūru un uzstādīšanu vai uzturēšanas paketi no vairākiem pakalpojumiem, piedāvājumā vienlaikus nepieciešamas divas lietas: sastāvam jābūt redzamam pasūtījumā, lai noliktava, tehniskais personāls un rēķinu izrakstīšana zinātu, kas tiek piegādāts. Taču klientam paredzētajā izdrukā ne vienmēr jābūt redzamai katrai atsevišķai pozīcijai ar katru atsevišķo cenu.
OCA modulis sale_product_set ļauj ar vienu klikšķi ievietot piedāvājumā produktu komplektus (pārdošanas materiālu sarakstus). Par drukas izskatu tas neizlemj. Tāpēc mēs izstrādājām moduli Sale Product Set Layout (sale_product_set_layout). Tas ir uzrakstīts Odoo 19 un kā brīvā programmatūra ar AGPL-3 licenci ir bez maksas pieejams GitHub:
github.com/Alex0176/odoo-sale-product-set-layout
Šī raksta saturs
- Problēma: produktu komplekti bez ietekmes uz drukas izskatu
- Ko modulis dara
- Trīs drukas režīmi detalizēti
- Paslēptas rindas un fiksēta cena
- Tehniskais risinājums
- Uzstādīšana bez nevēlamām blakusparādībām
- Lietošana soli pa solim
- Testi
- Ierobežojumi un juridiska piezīme
- Biežāk uzdotie jautājumi
- Biricon IT Services atbalsts
Problēma: produktu komplekti bez ietekmes uz drukas izskatu
Produktu komplekts Odoo ir sagatavots produktu saraksts ar daudzumiem. Tā vietā, lai meklētu desmit artikulus pa vienam, piedāvājumā izvēlas Pievienot komplektu un saņem visas rindas uzreiz. Tas ietaupa laiku un novērš aizmirstas pozīcijas. Modulis sale_product_set no repozitorija OCA/sale-workflow dara tieši to; paši komplekti nāk no product_set repozitorijā OCA/product-attribute.
Praksē paliek trīs nepilnības:
- Nav redzamas grupēšanas. Komplekta rindas piedāvājumā nonāk kā atsevišķas pozīcijas. Pēc ievietošanas vairs nav redzams, kuras rindas pieder kopā, un komplekta kopsumma nav redzama nekur.
- Nav ietekmes uz izdruku. Reizēm klientam jāredz katra pozīcija ar cenu, reizēm tikai paketes cena, reizēm tikai viena rinda. Tas ir lēmums katram komplektam vai katram klientam, nevis katrā piedāvājumā no jauna ar roku.
- Cenu korekcijas izskatās neglīti. Ja paketei jābūt ar fiksētu cenu, kas atšķiras no cenrāža cenu summas, nepieciešama korekcijas rinda. Tai jābūt aprēķinā, bet ne obligāti uz klienta papīra.
Odoo 19 piedāvā būvelementus, lai to atrisinātu tīri: sadaļas un apakšsadaļas piedāvājuma rindās ar opcijām Paslēpt cenas un Paslēpt sastāvu (lauki collapse_prices un collapse_composition). Modulis saista produktu komplektu ar šīm standarta opcijām, nevis izgudro savu drukas formātu.
Ko modulis dara
- Komplekta ievietošana kā sadaļa. Palīgs Pievienot komplektu izveido sadaļas rindu ar komplekta nosaukumu, piemēram, 2 × Messkit Standard, un zem tās ievieto komplekta rindas. Komplekta iekšējās sadaļas kļūst par apakšsadaļām.
- Drukas režīms katram komplektam. Komplektā vienreiz nosaka, kā tas tiek drukāts. Ievietojot šo režīmu var mainīt palīgā tikai konkrētajam gadījumam.
- Rindu paslēpšana. Atsevišķas rindas var atzīmēt kā Nedrukāt (komplektā: Paslēpta). Tās tiek ieskaitītas kopsummā, bet netiek ne drukātas, ne rādītas klientu portālā. Šī atzīme no piedāvājuma pāriet uz rēķinu.
- Fiksēta cena katrai komplekta rindai. Komplekta rindai var būt fiksēta vienības cena, kas aizstāj cenrāža cenu, piemēram, paslēptai cenu korekcijai.
Bez moduļa (tikai sale_product_set) | Ar sale_product_set_layout |
|---|---|
| Komplekta rindas kā atsevišķas pozīcijas | Sadaļas rinda ar komplekta nosaukumu, daudzums nosaukumā, rindas zem tās |
| Komplekta sadaļas paliek sadaļas un sagrauj struktūru | Komplekta sadaļas kļūst par apakšsadaļām (line_subsection) |
| Drukas izskats vienmēr vienāds | Drukas režīms katram komplektam, ievietojot maināms |
| Cenu korekcija redzama piedāvājumā un rēķinā | Rindu var paslēpt, bet tā tiek ieskaitīta kopsummā |
| Cena tikai no cenrāža | Pēc izvēles fiksēta cena katrai komplekta rindai |
| Izkārtojums beidzas ar piedāvājumu | Izkārtojums un paslēpšana attiecas uz piedāvājumu, pasūtījumu, rēķinu un klientu portālu |
Trīs drukas režīmi detalizēti
Drukas režīms ir izvēles lauks print_mode produktu komplektam. Ievietojot to pārveido par abiem sadaļas rindas standarta slēdžiem. Šim nolūkam modulī ir viens, viegli lasāms atbilstības saraksts:
# Druckmodus -> (collapse_prices, collapse_composition) der Abschnittszeile
PRINT_MODE_FLAGS = {
"detailed": (False, False),
"total_only": (True, False),
"summary": (False, True),
}
Režīms (print_mode) | Attēlojums komplektā | Standarta opcija Odoo | Drukas izskats |
|---|---|---|---|
detailed | Katra rinda ar cenu | nav | Sadaļa, visas rindas ar summu |
total_only | Rindas bez cenām, tikai komplekta kopsumma | collapse_prices (Paslēpt cenas) | Sadaļa ar kopsummu, rindas tikai ar nosaukumu un daudzumu |
summary | Tikai viena rinda ar komplekta kopsummu | collapse_composition (Paslēpt sastāvu) | Tikai sadaļas rinda ar kopsummu |
Tā kā modulis izmanto Odoo 19 standarta opcijas, nevis savu drukas formātu, piedāvājums, pasūtījuma apstiprinājums, rēķins un klientu portāls darbojas bez pielāgotām atskaišu veidnēm. Arī tiem, kam ir savas atskaišu veidnes, kas ņem vērā sadaļu opcijas, tiek nodrošināta tāda pati darbība.
Paslēptas rindas un fiksēta cena
Bieži sastopams gadījums: paketei ir paketes cena, kas ir zemāka par atsevišķo cenu summu. Tā vietā, lai izkropļotu atsevišķās cenas, izmanto korekcijas rindu ar fiksētu cenu (piemēram, −50,00 € katram komplektam) un to paslēpj. Aizmugursistēmā rēķins ir izsekojams, bet izdrukā ir redzama paketes cena.
Svarīgi izpratnei: atzīme hide_in_report neko nemaina aprēķinā. Daudzums, cena, atlaide, nodoklis, kopsummas un grāmatojumi veidojas nemainīti ar standarta Odoo. Rinda trūkst tikai izdrukā un portālā.
- Produktu komplektā: komplekta rinda ar Paslēpta un pēc izvēles Fiksēta cena kopā ar Vienības cena.
- Piedāvājuma un rēķina rindās: kolonna Nedrukāt (
hide_in_report), arī parastām rindām bez komplekta. - Nodošana tālāk: veidojot rēķinu no pasūtījuma, atzīme tiek pārnesta uz rēķina rindu. Kopējot piedāvājumu, tā saglabājas.
Tehniskais risinājums
Modulis ir apzināti mazs: tas paplašina esošos modeļus un pārraksta tikai tās vietas, kur Odoo izlemj, kuras rindas tiek drukātas un kā komplekts tiek ievietots. Nav jaunu atskaišu veidņu, nav jaunu modeļu un nav SQL iejaukšanās.
Paplašinātie modeļi un lauki
| Modelis | Papildinājums |
|---|---|
product.set | Lauki insert_as_section (Boolean, pēc noklusējuma ieslēgts) un print_mode (izvēle, obligāts lauks, pēc noklusējuma detailed) |
product.set.line | Lauki hide_in_report, fixed_price, price_unit; prepare_sale_order_line_values() nodod tos tālāk piedāvājuma rindai |
sale.product.set.wizard | Lauki insert_as_section, section_name, print_mode; _prepare_order_lines() izveido sadaļas rindu |
sale.order / sale.order.line | Lauks hide_in_report (ar copy=True); _get_order_lines_to_report() izlaiž paslēptās rindas; _prepare_invoice_line() nodod atzīmi tālāk |
account.move / account.move.line | Lauks hide_in_report; _get_move_lines_to_report(), _get_detailed_lines() un _get_subsection_lines() filtrē paslēptās rindas; _get_aml_vals() ieraksta atzīmi atskaites datos |
Paslēpšana piedāvājumā
Odoo 19 nosaka drukājamās piedāvājuma rindas funkcijā _get_order_lines_to_report(). Modulis tur pievieno filtru. Iejaukšanās atskaites veidnē nav nepieciešama: gan piedāvājuma atskaites veidne (sale/report/ir_actions_report_templates.xml), gan portāla veidne (sale/views/sale_portal_templates.xml) izsauc šo metodi:
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
)
Nodošana rēķinam
Veidojot rēķina rindu no piedāvājuma rindas (_prepare_invoice_line()), atzīme tiek nokopēta. Rēķina pusē Odoo 19 ir vairāki ceļi, pa kuriem rindas nonāk atskaitē: galvenais saraksts, sadaļas rindas un apakšsadaļas rindas. Tāpēc modulis filtrē vairākās vietās (_get_move_lines_to_report() dokumentā, _get_detailed_lines() un _get_subsection_lines() rindā), citādi paslēpta rinda varētu atkal parādīties pa kādu no citiem ceļiem:
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")]
Palīgs: sadaļa atsevišķu rindu vietā
Palīgs sale.product.set.wizard no sale_product_set izveido piedāvājuma rindas funkcijā _prepare_order_lines(). Modulis šo metodi pārraksta. Ja Ievietot kā sadaļu ir izslēgts, tas vienkārši izsauc sākotnējo metodi, un darbība paliek tāda pati kā OCA modulī. Pretējā gadījumā vispirms rodas sadaļas rinda ar abiem standarta slēdžiem, pēc tam seko komplekta rindas. Komplekta iekšējās sadaļas kļūst par apakšsadaļām, lai tās nesagrautu galveno struktūru:
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
Lēmumi, kas nav redzami
- Atsevišķas aprēķina metodes palīgā. Sadaļas nosaukumam, drukas režīmam un Ievietot kā sadaļu katram ir sava
computemetode (store=True,readonly=False). Ja visiem trim būtu viena un tā pati metode, skaidri nodota vērtība vienam laukam atiestatītu pārējos. Tas īpaši krīt acīs, kad palīgs tiek izveidots no koda vai testiem ar vērtībām. - Sadaļas nosaukums ar daudzumu. Ja daudzums nav 1, tas ir norādīts nosaukumā (2 × Messkit Standard, ar komatu kā decimālatdalītāju), lai izdrukā būtu redzams, ka tie ir divi komplekti, nevis viens komplekts ar dubultu daudzumu.
- Fiksēta cena tikai produktu rindām.
prepare_sale_order_line_values()iestatahide_in_reportunprice_unittikai tad, ja komplekta rinda nav sadaļas vai piezīmes rinda. - Standarta Odoo, nevis pašbūve. Drukas režīms un paslēpšana izmanto Odoo 19 esošos āķus (hooks) un laukus. Tas padara atjauninājumus kontrolējamus: ja Odoo maina atskaites veidni, modulis paliek derīgs, kamēr metodes pastāv.
Uzstādīšana bez nevēlamām blakusparādībām
Priekšnoteikumi: Odoo 19.0, sale_product_set (OCA/sale-workflow, zars 19.0) un product_set (OCA/product-attribute, zars 19.0). Pats modulis ir atkarīgs no sale_management, sale_product_set un account.
auto_install lamatas OCA moduļos. Daudzi OCA repozitoriji satur moduļus ar auto_install. Tiklīdz ir pieejamas to atkarības, Odoo nākamās uzstādīšanas vai atjaunināšanas laikā tos uzstāda līdzi bez jautāšanas. Ja tāpēc viss OCA repozitorijs tiek ielikts produkcijas instances addons_path, var tikt uzstādīti moduļi, ko neviens nebija vēlējies. Repozitorijā OCA/product-attribute tas attiecas, piemēram, uz purchase_product_template_tags. Mūsu rīcība:
- Abus OCA repozitorijus klonēt seklajā veidā (
git clone --depth 1 --branch 19.0). - Atsevišķā direktorijā ar simbolisko saiti sasaistīt tikai divus nepieciešamos moduļus un šo direktoriju pievienot
addons_path, nevis veselos repozitorijus. - Uzstādīt testa datubāzē un pārbaudīt, kuriem moduļiem tā laikā tiek piešķirts statuss uzstādīts.
- Tikai tad uzstādīt produkcijā, ar
--workers=0, lai izsaukums nekonkurētu ar darbojošos pakalpojumu par HTTP portu.
odoo-bin -c /etc/odoo/odoo.conf -d <datenbank> -i sale_product_set_layout --stop-after-init
Jaunie lauki un skati pēc uzstādīšanas atrodas datubāzē. Ja pakalpojums darbojas daudzprocesu režīmā, worker procesi pārlādē mainīto reģistru, izmantojot datubāzes signālu. Moduļa Python failu izmaiņas stājas spēkā tikai pēc pakalpojuma restartēšanas.
Lietošana soli pa solim
- Komplekta izveide: Pārdošana → Produkti → Produktu komplekti. Nosaukt komplektu, izvēlēties Ievietot kā sadaļu un Drukas režīms, ievadīt produktus ar daudzumiem. Korekcijas rindām norādīt Paslēpta un Fiksēta cena.
- Piedāvājumā: noklikšķināt uz Pievienot komplektu, izvēlēties komplektu un daudzumu. Sadaļas nosaukumu un drukas režīmu var mainīt pirms ievietošanas.
- Atsevišķu rindu paslēpšana: piedāvājumā vai rēķinā aktivizēt kolonnu Nedrukāt.
- Pārbaude: atvērt priekšskatījumu vai PDF. Tādu pašu attēlojumu klienti redz portālā.
Testi
Modulis nāk ar sešiem automatizētiem testiem, ko izpildām testa datubāzē, pirms kaut kas nonāk produkcijā:
- Ievietošana kā sadaļa, ieskaitot drukas režīmu un apakšsadaļu
- Paslēptā rinda nav drukājamo rindu sarakstā
- Režīms Viena rinda (
summary) - Ievietošana bez sadaļas, sākotnējā darbība
- Rēķins pārņem atzīmi
hide_in_report, rinda nav_get_move_lines_to_report(), sadaļas kopsumma to joprojām ietver - Rēķins režīmā Tikai kopējā cena nerāda paslēpto rindu sadaļas rindās, sadaļas kopsumma paliek pilnīga
odoo-bin -d <testdatenbank> -i sale_product_set_layout \
--test-enable --test-tags=/sale_product_set_layout --stop-after-init
Tulkojums vācu valodā atrodas failā i18n/de.po.
Ierobežojumi un juridiska piezīme
- Tikai izkārtojums. Modulis nemaina, kā Odoo aprēķina cenas, atlaides vai nodokļus. Tas maina tikai to, kas tiek drukāts un rādīts portālā.
- Paslēptās rindas aizmugursistēmā ir redzamas. Atzīme attiecas uz izdruku un portālu, nevis uz darbinieku ekrāna skatu.
- Pārbaudiet rēķinu datus. Paslēptās rindas tiek ieskaitītas kopsummā, bet nav redzamas dokumentā. Vai tas ir savienojams ar rēķiniem izvirzītajām prasībām Jūsu valstī, piemēram, ar noteikto piegādāto preču vai sniegto pakalpojumu aprakstu, Jums jāizskaidro ar savu nodokļu konsultantu pirms izmantošanas rēķiniem. Piedāvājumos paslēpšana ir mazāk problemātiska. Raksts nav juridiska konsultācija.
- Pārbaudīts Odoo 19. Moduli esam izstrādājuši un pārbaudījuši Odoo 19.0 Community. Tas izmanto sadaļu opcijas, kas šādā veidā ir pieejamas Odoo 19. Citām versijām mēs to neesam pārbaudījuši.
Biežāk uzdotie jautājumi
Kāpēc man vajadzīgs modulis, ja Odoo 19 jau prot sadaļas?
Sadaļu opcijas ir pašā Odoo. Trūka saiknes ar produktu komplektu: komplektam bija jāievietojas automātiski kā sadaļai ar komplektā norādīto drukas režīmu. Bez moduļa pēc katras ievietošanas sadaļas rinda jāizveido un jānokonfigurē ar roku.
Kā atšķiras „Paslēpt cenas” un „Paslēpt sastāvu”?
„Paslēpt cenas” (collapse_prices) atstāj rindas, bet nerāda summas, tikai kopsummu sadaļā. „Paslēpt sastāvu” (collapse_composition) rindas paslēpj pavisam, klients redz tikai sadaļu ar kopsummu.
Vai paslēpta rinda tiek ieskaitīta rēķina kopsummā?
Jā. Paslēptās rindas paliek kopsummā, nodoklī un grāmatojumā. Atzīme attiecas tikai uz attēlojumu izdrukā un klientu portālā.
Vai drukas režīmu ievietošanas brīdī vēl var mainīt?
Jā. Režīms tiek pārņemts kā noklusējums no komplekta, palīgā to var mainīt konkrētajai ievietošanai. Pats komplekts tajā pašā laikā paliek nemainīts.
Kas notiek, ja izslēdzu Ievietot kā sadaļu?
Tad palīgs darbojas tāpat kā OCA modulī sale_product_set: komplekta rindas tiek ievietotas bez sadaļas.
Vai modulis negaidīti uzstāda citus moduļus?
Pats modulis nē. Taču OCA repozitorijiem var rasties auto_install moduļi, ja addons_path ieliek veselus repozitorijus. Tāpēc sasaistiet tikai abus nepieciešamos moduļus (skatiet sadaļu Uzstādīšana).
Vai modulis darbojas ar Odoo Enterprise?
Modulis ir atkarīgs tikai no Community moduļiem (sale_management, account) un abiem OCA moduļiem. Mēs to izmantojam Odoo 19 Community. Ar Enterprise mēs to neesam pārbaudījuši.
Kādai licencei modulis pakļauts?
AGPL-3. Jūs drīkstat to izmantot, pielāgot un izplatīt, ja vien izmaiņas paliek zem tās pašas licences. Kļūdu ziņojumi un uzlabojumu ieteikumi ir laipni gaidīti kā issue GitHub repozitorijā .
Biricon IT Services atbalsts
Mēs apkalpojam Odoo instalācijas mazajiem un vidējiem uzņēmumiem: no ieviešanas, pielāgojumiem un migrācijām līdz pastāvīgai darbībai. Ja vēlaties pielāgot produktu komplektus, piedāvājumu veidnes vai atskaites Odoo 19 savām darba norisēm vai ja vēlaties pārbaudīt tādu moduli kā šis un droši ievest to savā produkcijas instancē, mēs labprāt palīdzēsim. Citas pašu izstrādes atradīsiet mūsu blogā, piemēram, Rēķinu melnrakstu apvienošana un Bankas maksājumu automātiska piesaiste rēķiniem.
Stāvoklis uz 2026. gada 2. novembri. Moduļa versija 19.0.1.0.0. Attēlos izmantotie piemēru dati ir brīvi izvēlēti, summas bez PVN.