Skip to content

Commit 4bff046

Browse files
author
kuay-odoo
committed
[ADD] supplier_portal: allow suppliers to upload invoices from portal
Introduce a supplier-facing portal feature to streamline invoice submission. Features: - Allow authenticated users in the `Supplier User` group to upload invoices via website form. - Security: - Access restricted to users in the `Supplier User` group. - CSRF token protection for form submissions. - Company selection: - Lists companies linked to the user. - Allows user to select the target company for invoice submission. - File handling: - Uploaded files are stored as attachments. - Vendor bill is associated with a purchase journal from the selected company. - Confirmation message shown upon successful submission. - Adds a new security group: `Supplier User` and website menu item Upload Invoice, visible only to users in the `Supplier User` group. Benefits: - Enables suppliers to directly submit invoice files from the portal. - Improves workflow efficiency and reduces manual data entry for internal teams.
1 parent 61161ab commit 4bff046

File tree

7 files changed

+165
-0
lines changed

7 files changed

+165
-0
lines changed

supplier_portal/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from . import controllers

supplier_portal/__manifest__.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"name": "Supplier Portal",
3+
"description": """
4+
Help supplier to provide their Invoice
5+
""",
6+
"category": "Vendor",
7+
"version": "1.0",
8+
"depends": ["account", "website"],
9+
"data": [
10+
"security/supplier_group.xml",
11+
"views/supplier_template.xml",
12+
"views/website_menu.xml",
13+
],
14+
"auto-install": True,
15+
"application": False,
16+
"license": "LGPL-3",
17+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from . import main

supplier_portal/controllers/main.py

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
from odoo import http
2+
from odoo.http import request
3+
import base64
4+
from odoo.exceptions import UserError
5+
6+
7+
class SupplierPortal(http.Controller):
8+
@http.route(["/upload-invoice"], type="http", auth="user", website=True)
9+
def supplier_upload_page(self, **kwargs):
10+
user = request.env.user
11+
if not user.has_group("supplier_portal.group_supplier_portal"):
12+
raise UserError("Only Supplier Group Users allowed!")
13+
14+
companies = (
15+
request.env["res.company"].sudo().search([("user_ids", "in", [user.id])])
16+
)
17+
18+
return request.render(
19+
"supplier_portal.upload_invoice_template",
20+
{
21+
"companies": companies,
22+
},
23+
)
24+
25+
@http.route(
26+
["/submit-invoice"],
27+
type="http",
28+
auth="user",
29+
methods=["POST"],
30+
csrf=True,
31+
website=True,
32+
)
33+
def submit_invoice(self, **post):
34+
pdf_file = post.get("pdf_file")
35+
xml_file = post.get("xml_file")
36+
company_id = int(post.get("company_id"))
37+
38+
pdf_content = pdf_file.read() if pdf_file else b""
39+
xml_content = xml_file.read() if xml_file else b""
40+
41+
journal = (
42+
request.env["account.journal"]
43+
.sudo()
44+
.search(
45+
[("type", "=", "purchase"), ("company_id", "=", company_id)], limit=1
46+
)
47+
)
48+
49+
if not journal:
50+
company = request.env["res.company"].sudo().browse(company_id)
51+
raise UserError(f"No journal found for company: {company.name}")
52+
53+
move_vals = {
54+
"move_type": "in_invoice",
55+
"partner_id": request.env.user.id,
56+
"state": "draft",
57+
"company_id": company_id,
58+
"journal_id": journal.id,
59+
}
60+
61+
move = request.env["account.move"].sudo().create(move_vals)
62+
63+
if pdf_content:
64+
request.env["ir.attachment"].sudo().create(
65+
{
66+
"name": pdf_file.filename,
67+
"type": "binary",
68+
"datas": base64.b64encode(pdf_content),
69+
"res_model": "account.move",
70+
"res_id": move.id,
71+
"mimetype": "application/pdf",
72+
}
73+
)
74+
if xml_content:
75+
request.env["ir.attachment"].sudo().create(
76+
{
77+
"name": xml_file.filename,
78+
"type": "binary",
79+
"datas": base64.b64encode(xml_content),
80+
"res_model": "account.move",
81+
"res_id": move.id,
82+
"mimetype": "text/xml",
83+
}
84+
)
85+
86+
return request.redirect("/upload-invoice?success=1")
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<odoo>
3+
<data noupdate="0">
4+
<record id="group_supplier_portal" model="res.groups">
5+
<field name="name">Supplier User</field>
6+
<field name="category_id" ref="base.module_category_vendor" />
7+
</record>
8+
</data>
9+
</odoo>
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<odoo>
3+
<template id="upload_invoice_template">
4+
<t t-call="website.layout">
5+
<div class="container mt-5">
6+
<h2>Upload Invoice</h2>
7+
<t t-if="request.params.get('success')">
8+
<div class="alert alert-success">Invoice submitted successfully!</div>
9+
</t>
10+
<form t-attf-action="/submit-invoice" method="POST" enctype="multipart/form-data">
11+
<input type="hidden" name="csrf_token" t-att-value="request.csrf_token()" />
12+
13+
<div class="form-group">
14+
<label>Select Company</label>
15+
<select name="company_id" class="form-control" required="1">
16+
<t t-foreach="companies" t-as="company">
17+
<option t-att-value="company.id">
18+
<t t-esc="company.name" />
19+
</option>
20+
</t>
21+
</select>
22+
</div>
23+
24+
<div class="form-group">
25+
<label>Upload PDF</label>
26+
<input type="file" name="pdf_file" accept=".pdf" class="form-control"
27+
required="1" />
28+
</div>
29+
<div class="form-group">
30+
<label>Upload XML</label>
31+
<input type="file" name="xml_file" accept=".xml" class="form-control" required="1"/>
32+
</div>
33+
34+
<button type="submit" class="btn btn-primary mt-3">Submit Invoice</button>
35+
</form>
36+
</div>
37+
</t>
38+
</template>
39+
</odoo>
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<odoo>
3+
<data noupdate="0">
4+
<record id="menu_upload_invoice" model="website.menu">
5+
<field name="name">Upload Invoice</field>
6+
<field name="url">/upload-invoice</field>
7+
<field name="parent_id" ref="website.main_menu" />
8+
<field name="sequence">50</field>
9+
<field name="group_ids" eval="[(4, ref('supplier_portal.group_supplier_portal'))]" />
10+
</record>
11+
</data>
12+
</odoo>

0 commit comments

Comments
 (0)