Repository
OCA/purchase-workflow · module folder · Try on Runboat
Module version
1.0.2
Category
Purchase Management
Folder size
4.09 MB
License
LGPL-3
Application
Yes
Auto-installable
No
Website
https://github.com/OCA/purchase-workflow
Last tracking update
2026-08-17 18:05:56
Authors
Odoo Community Association (OCA), ForgeFlow
Maintainers
Odoo Community Association (OCA), ForgeFlow
Committers
David Vidal, Weblate, OCA-git-bot, oca-ci, Hector Vior, Bhavesh Heliconia, mav-adhoc
Odoo dependencies
Python dependencies
None
System dependencies
None
Required by
purchase_request_tier_validation
Description
You use this module if you wish to give notification of requirements of
materials and/or external services and keep track of such requirements.

Requests can be created either directly or indirectly. "Directly" means
that someone from the requesting department enters a purchase request
manually.

The person creating the request determines what and how much to order,
and the requested date.

"Indirectly" means that the purchase request initiated by the
application automatically, for example, from procurement orders (MO,
SO).

A purchase request is an instruction to Purchasing to procure a certain
quantity of materials services, so that they are available at a certain
point in time.

A line of a request contains the quantity and requested date of the
material to be supplied or the quantity of the service to be performed.
You can indicate the service specifications if needed.

Once request is approved go to the Purchase Request Lines from the menu
entry 'Purchase Requests', and also from the 'Purchase' menu.

Select the lines that you wish to initiate the RFQ for, then go to
'More' and press 'Create RFQ'.

You can choose to select an existing RFQ or create a new one. In the
later, you have to choose a supplier.

In case that you chose to select an existing RFQ, the application will
search for existing lines matching the request line, and will add the
extra quantity to them, recalculating the minimum order quantity, if it
exists for the supplier of that RFQ.

In case that you create a new RFQ, the request lines will also be
consolidated into as few as possible lines in the RFQ.

Code Analysis

Views touched (20)
XML IDNameModelTypeStatus
product_template_form_view_inherit product.template.form.inherit product.template form Inherits stock.view_template_property_form
purchase_order_form purchase.order.form purchase.order form Inherits purchase.purchase_order_form
purchase_order_line_form2 purchase.order.line.form2 purchase.order.line Inherits purchase.purchase_order_line_form2
purchase_order_line_form2_sub purchase.order.line.form2 purchase.order.line form New
purchase_order_line_search_sub purchase.order.line.search purchase.order.line search New
purchase_order_line_tree purchase.order.line.list purchase.order.line list Inherits purchase.purchase_order_line_tree
purchase_order_line_tree_sub purchase.order.line.list purchase.order.line list New
purchase_request_allocation purchase.request.allocation purchase.request.allocation list New
purchase_request_line_form purchase.request.line.form purchase.request.line form New
purchase_request_line_search purchase.request.line.search purchase.request.line search New
purchase_request_line_tree purchase.request.line.list purchase.request.line list New
report_purchase_request report_purchase_request ir.ui.view qweb New
view_move_form stock.move.form stock.move form Inherits stock.view_move_form
view_purchase_request_form purchase.request.form purchase.request form New
view_purchase_request_kanban purchase.request.kanban purchase.request kanban New
view_purchase_request_line_details purchase.request.line.details.form purchase.request.line form New
view_purchase_request_line_make_purchase_order Purchase Request Line Make Purchase Order purchase.request.line.make.purchase.order form New
view_purchase_request_search purchase.request.list.select purchase.request search New
view_purchase_request_tree purchase.request.list purchase.request list New
view_stock_move_operations stock.move.operations.form stock.move form Inherits stock.view_stock_move_operations
HTTP endpoints (0)

No HTTP endpoints found for this module.

Models touched (12)

New fields (1)
  • purchase_request Boolean
    company_dependent=True help='Check this box to generate Purchase Request instead of generating Requests For Quotation from procurement.'
Public methods (0)

No public methods.

New fields (0)

No new fields.

Public methods (2)
  • button_confirm(self)
  • unlink(self)

New fields (2)
  • purchase_request_allocation_ids One2many → purchase.request.allocation
    comodel_name='purchase.request.allocation' copy=False inverse_name='purchase_line_id'
  • purchase_request_lines Many2many → purchase.request.line
    column1='purchase_order_line_id' column2='purchase_request_line_id' comodel_name='purchase.request.line' copy=False readonly=True relation='purchase_request_purchase_order_line_rel'
Public methods (3)
  • action_open_request_line_tree_view(self)
    :return dict: dictionary value for created view
  • update_service_allocations(self, prev_qty_received)
  • write(self, vals)

New fields (19)
  • assigned_to Many2one → res.users
    comodel_name='res.users' domain=<expr> index=True string='Approver' tracking=True
  • company_id Many2one → res.company
    comodel_name='res.company' default=<expr> required=False tracking=True
  • currency_id Many2one
    readonly=True related='company_id.currency_id'
  • date_start Date
    default=fields.Date.context_today help='Date when the user initiated the request.' string='Creation date' tracking=True
  • description Text
  • estimated_cost Monetary
    compute='_compute_estimated_cost' store=True string='Total Estimated Cost'
  • is_editable Boolean
    compute='_compute_is_editable' readonly=True
  • is_name_editable Boolean
    default=<expr>
  • line_count Integer
    compute='_compute_line_count' readonly=True string='Purchase Request Line count'
  • line_ids One2many → purchase.request.line
    comodel_name='purchase.request.line' copy=True inverse_name='request_id' readonly=False string='Products to Purchase' tracking=True
  • move_count Integer
    compute='_compute_move_count' readonly=True string='Stock Move count'
  • name Char
    default=<expr> required=True string='Request Reference' tracking=True
  • origin Char
    string='Source Document'
  • picking_type_id Many2one → stock.picking.type
    comodel_name='stock.picking.type' default=<expr> required=True
  • product_id Many2one → product.product
    comodel_name='product.product' readonly=True related='line_ids.product_id' string='Product'
  • purchase_count Integer
    compute='_compute_purchase_count' readonly=True string='Purchases count'
  • requested_by Many2one → res.users
    comodel_name='res.users' copy=False default=<expr> index=True required=True tracking=True
  • state Selection
    copy=False default='draft' index=True required=True selection=_STATES string='Status' tracking=True
  • to_approve_allowed Boolean
    compute='_compute_to_approve_allowed'
Public methods (14)
  • action_view_purchase_order(self)
  • action_view_purchase_request_line(self)
  • action_view_stock_picking(self)
  • button_approved(self)
  • button_done(self)
  • button_draft(self)
  • button_in_progress(self)
  • button_rejected(self)
  • button_to_approve(self)
  • check_auto_reject(self)
    When all lines are cancelled the purchase request should be auto-rejected.
  • copy(self, default=None)
  • create(self, vals_list)
    @api.model_create_multi
  • to_approve_allowed_check(self)
  • write(self, vals)

New fields (10)
  • allocated_product_qty Float
    copy=False help='Quantity of the purchase request line allocated to the stockmove, in the default UoM of the product' string='Allocated Quantity'
  • company_id Many2one → res.company
    comodel_name='res.company' index=True readonly=True related='purchase_request_line_id.request_id.company_id' store=True
  • open_product_qty Float
    compute='_compute_open_product_qty' string='Open Quantity'
  • product_id Many2one → product.product
    comodel_name='product.product' readonly=True related='purchase_request_line_id.product_id' string='Product'
  • product_uom_id Many2one → uom.uom
    comodel_name='uom.uom' readonly=True related='purchase_request_line_id.product_uom_id' required=True string='UoM'
  • purchase_line_id Many2one → purchase.order.line
    comodel_name='purchase.order.line' copy=True help='Service Purchase Order Line' index=True ondelete='cascade'
  • purchase_request_line_id Many2one → purchase.request.line
    comodel_name='purchase.request.line' copy=True index=True ondelete='cascade' required=True
  • purchase_state Selection
    related='purchase_line_id.state'
  • requested_product_uom_qty Float
    help='Quantity of the purchase request line allocated to thestock move, in the UoM of the Purchase Request Line' string='Requested Quantity'
  • stock_move_id Many2one → stock.move
    comodel_name='stock.move' index=True ondelete='cascade'
Public methods (0)

No public methods.

New fields (30)
  • assigned_to Many2one → res.users
    comodel_name='res.users' related='request_id.assigned_to' store=True string='Assigned to'
  • cancelled Boolean
    copy=False default=False readonly=True
  • company_id Many2one → res.company
    comodel_name='res.company' index=True related='request_id.company_id' store=True string='Company'
  • currency_id Many2one
    readonly=True related='company_id.currency_id'
  • date_required Date
    default=fields.Date.context_today required=True string='Request Date' tracking=True
  • date_start Date
    related='request_id.date_start' store=True
  • description Text
    readonly=False related='request_id.description' store=True string='PR Description'
  • estimated_cost Monetary
    currency_field='currency_id' default=0.0 help='Estimated cost of Purchase Request Line, not propagated to PO.'
  • is_editable Boolean
    compute='_compute_is_editable' readonly=True
  • move_dest_ids One2many → stock.move
    comodel_name='stock.move' inverse_name='created_purchase_request_line_id' string='Downstream Moves'
  • name Char
    string='Description' tracking=True
  • orderpoint_id Many2one → stock.warehouse.orderpoint
    comodel_name='stock.warehouse.orderpoint'
  • origin Char
    related='request_id.origin' store=True string='Source Document'
  • pending_qty_to_receive Float
    compute='_compute_qty_to_buy' copy=False digits='Product Unit of Measure' store=True string='Pending Qty to Receive'
  • product_id Many2one → product.product
    comodel_name='product.product' domain=[('purchase_ok', '=', True)] tracking=True
  • product_qty Float
    digits='Product Unit of Measure' string='Quantity' tracking=True
  • product_uom_id Many2one → uom.uom
    comodel_name='uom.uom' string='UoM' tracking=True
  • purchase_lines Many2many → purchase.order.line
    column1='purchase_request_line_id' column2='purchase_order_line_id' comodel_name='purchase.order.line' copy=False readonly=True relation='purchase_request_purchase_order_line_rel' string='Purchase Order Lines'
  • purchase_request_allocation_ids One2many → purchase.request.allocation
    comodel_name='purchase.request.allocation' inverse_name='purchase_request_line_id'
  • purchase_state Selection
    compute='_compute_purchase_state' selection=<expr> store=True string='Purchase Status'
  • purchased_qty Float
    compute='_compute_purchased_qty' digits='Product Unit of Measure' string='RFQ/PO Qty'
  • qty_cancelled Float
    compute='_compute_qty_cancelled' digits='Product Unit of Measure' help='Quantity cancelled' readonly=True store=True
  • qty_done Float
    compute='_compute_qty' digits='Product Unit of Measure' help='Quantity completed' readonly=True store=True
  • qty_in_progress Float
    compute='_compute_qty' digits='Product Unit of Measure' help='Quantity in progress.' readonly=True store=True
  • qty_to_buy Boolean
    compute='_compute_qty_to_buy' store=True string='There is some pending qty to buy'
  • request_id Many2one → purchase.request
    comodel_name='purchase.request' index=True ondelete='cascade' readonly=True string='Purchase Request'
  • request_state Selection
    related='request_id.state' store=True string='Request state'
  • requested_by Many2one → res.users
    comodel_name='res.users' related='request_id.requested_by' store=True string='Requested by'
  • specifications Text
  • supplier_id Many2one → res.partner
    comodel_name='res.partner' compute='_compute_supplier_id' compute_sudo=True store=True string='Preferred supplier'
Public methods (5)
  • action_show_details(self)
  • do_cancel(self)
    Actions to perform when cancelling a purchase request line.
  • do_uncancel(self)
    Actions to perform when uncancelling a purchase request line.
  • onchange_product_id(self)
    @api.onchange('product_id')
  • write(self, vals)

New fields (4)
  • item_ids One2many → purchase.request.line.make.purchase.order.item
    comodel_name='purchase.request.line.make.purchase.order.item' inverse_name='wiz_id'
  • purchase_order_id Many2one → purchase.order
    comodel_name='purchase.order' domain=[('state', '=', 'draft')]
  • supplier_id Many2one → res.partner
    comodel_name='res.partner' context={'res_partner_search_mode': 'supplier'} required=True
  • sync_data_planned Boolean
    help='When checked, PO lines on the selected purchase order are only reused if the scheduled date matches as well.' string='Match existing PO lines by Scheduled Date'
Public methods (4)
  • create_allocation(self, po_line, pr_line, new_qty, alloc_uom)
  • default_get(self, fields)
    @api.model
  • get_items(self, request_line_ids)
    @api.model
  • make_purchase_order(self)

New fields (8)
  • keep_description Boolean
    help='Set true if you want to keep the descriptions provided in the wizard in the new PO.' string='Copy descriptions to new PO'
  • line_id Many2one → purchase.request.line
    comodel_name='purchase.request.line' string='Purchase Request Line'
  • name Char
    required=True string='Description'
  • product_id Many2one → product.product
    comodel_name='product.product' readonly=False related='line_id.product_id' string='Product'
  • product_qty Float
    digits='Product Unit of Measure' string='Quantity to purchase'
  • product_uom_id Many2one → uom.uom
    comodel_name='uom.uom' required=True string='UoM'
  • request_id Many2one → purchase.request
    comodel_name='purchase.request' readonly=False related='line_id.request_id' string='Purchase Request'
  • wiz_id Many2one → purchase.request.line.make.purchase.order
    comodel_name='purchase.request.line.make.purchase.order' ondelete='cascade' readonly=True required=True string='Wizard'
Public methods (1)
  • onchange_product_id(self)
    @api.onchange('product_id')

New fields (3)
  • created_purchase_request_line_id Many2one → purchase.request.line
    comodel_name='purchase.request.line' copy=False index=True ondelete='set null' readonly=True
  • purchase_request_allocation_ids One2many → purchase.request.allocation
    comodel_name='purchase.request.allocation' copy=False inverse_name='stock_move_id'
  • purchase_request_ids One2many → purchase.request
    comodel_name='purchase.request' compute='_compute_purchase_request_ids'
Public methods (1)
  • copy_data(self, default=None)
    Propagate request allocation on copy. If this move is being split, or if this move is processed and there is a remaining allocation, move the appropriate quantity over to the new move.

New fields (0)

No new fields.

Public methods (1)
  • allocate(self)

New fields (0)

No new fields.

Public methods (2)
  • create_purchase_request(self, procurement_group)
    Create a purchase request containing procurement order product.
  • is_create_purchase_request_allowed(self, procurement)
    Tell if current procurement order should create a purchase request or not. :return: boolean

New fields (0)

No new fields.

Public methods (0)

No public methods.

Loading…

Loading…

Loading…

Loading…

Loading…

Loading…

Loading…

Loading…

Loading…

Loading…

Loading…