Skip to Content

Odoo 19 Community: produktu komplekti piedāvājumā kā sadaļa – mūsu atvērtā koda modulis Sale Product Set Layout

2026. gada 2. novembris | Odoo 19 Community | Pašu izstrāde
2026. gada 2. novembris by
Odoo 19 Community: produktu komplekti piedāvājumā kā sadaļa – mūsu atvērtā koda modulis Sale Product Set Layout

Odoo 19 modulis Sale Product Set Layout: produktu komplekti kā piedāvājuma sadaļa ar drukas režīmu, paslēptām rindām un fiksētu cenu

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

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

  1. 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.
  2. 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.
  3. 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.
  4. 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īcijasSadaļas rinda ar komplekta nosaukumu, daudzums nosaukumā, rindas zem tās
Komplekta sadaļas paliek sadaļas un sagrauj struktūruKomplekta sadaļas kļūst par apakšsadaļām (line_subsection)
Drukas izskats vienmēr vienādsDrukas 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āžaPēc izvēles fiksēta cena katrai komplekta rindai
Izkārtojums beidzas ar piedāvājumuIzkā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),
}

Trīs viena un tā paša produktu komplekta drukas izskati: katra rinda ar cenu, tikai kopējā cena, tikai viena rinda

Režīms (print_mode)Attēlojums komplektāStandarta opcija OdooDrukas izskats
detailedKatra rinda ar cenunavSadaļa, visas rindas ar summu
total_onlyRindas bez cenām, tikai komplekta kopsummacollapse_prices (Paslēpt cenas)Sadaļa ar kopsummu, rindas tikai ar nosaukumu un daudzumu
summaryTikai viena rinda ar komplekta kopsummucollapse_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.

Cenu korekcija aizmugursistēmā redzama un atzīmēta, piedāvājuma, PDF, rēķina un portāla izdrukā nav redzama, kopsumma identiska

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.

Datu plūsma: produktu komplekts, palīgs Pievienot komplektu, piedāvājuma rindas, rēķina rindas, PDF un klientu portāls

Paplašinātie modeļi un lauki

ModelisPapildinājums
product.setLauki 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.lineLauki hide_in_report, fixed_price, price_unit; prepare_sale_order_line_values() nodod tos tālāk piedāvājuma rindai
sale.product.set.wizardLauki insert_as_section, section_name, print_mode; _prepare_order_lines() izveido sadaļas rindu
sale.order / sale.order.lineLauks 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.lineLauks 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 compute metode (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() iestata hide_in_report un price_unit tikai 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:

  1. Abus OCA repozitorijus klonēt seklajā veidā (git clone --depth 1 --branch 19.0).
  2. Atsevišķā direktorijā ar simbolisko saiti sasaistīt tikai divus nepieciešamos moduļus un šo direktoriju pievienot addons_path, nevis veselos repozitorijus.
  3. Uzstādīt testa datubāzē un pārbaudīt, kuriem moduļiem tā laikā tiek piešķirts statuss uzstādīts.
  4. 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

  1. 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.
  2. 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.
  3. Atsevišķu rindu paslēpšana: piedāvājumā vai rēķinā aktivizēt kolonnu Nedrukāt.
  4. 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.

Sazināties tagad

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.