@ -0,0 +1,48 @@ |
|||
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg |
|||
:target: https://www.gnu.org/licenses/agpl-3.0-standalone.html |
|||
:alt: License: AGPL-3 |
|||
|
|||
All In One Website Kit |
|||
====================== |
|||
All In One Website Kit for odoo15 enables multiple website features. |
|||
|
|||
Configuration |
|||
============= |
|||
* No additional configurations needed |
|||
|
|||
Company |
|||
------- |
|||
* `Cybrosys Techno Solutions <https://cybrosys.com/>`__ |
|||
|
|||
License |
|||
------- |
|||
Affero General Public License, Version 3 (AGPL v3). |
|||
(https://www.gnu.org/licenses/agpl-3.0-standalone.html) |
|||
|
|||
Credits |
|||
------- |
|||
* Developers: (V15) Aysha Shalin, |
|||
(V16) Yadhukrishnan, |
|||
Contact: odoo@cybrosys.com |
|||
|
|||
Contacts |
|||
-------- |
|||
* Mail Contact : odoo@cybrosys.com |
|||
* Website : https://cybrosys.com |
|||
|
|||
Bug Tracker |
|||
----------- |
|||
Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. |
|||
|
|||
Maintainer |
|||
========== |
|||
.. image:: https://cybrosys.com/images/logo.png |
|||
:target: https://cybrosys.com |
|||
|
|||
This module is maintained by Cybrosys Technologies. |
|||
|
|||
For support and more information, please visit `Our Website <https://cybrosys.com/>`__ |
|||
|
|||
Further information |
|||
=================== |
|||
HTML Description: `<static/description/index.html>`__ |
@ -0,0 +1,22 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################### |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: Aysha Shalin (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################### |
|||
from . import controllers, models |
@ -0,0 +1,95 @@ |
|||
# -*- coding: utf-8 -*- |
|||
################################################################################ |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: Aysha Shalin (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
################################################################################ |
|||
{ |
|||
'name': 'All In One Website Kit', |
|||
'version': '15.0.1.0.0', |
|||
'category': 'Website', |
|||
'summary': """All In One Website Kit for odoo16 community edition enables |
|||
multiple website features.""", |
|||
'description': """This module enables the features of the following modules, |
|||
Website Call For Price, Customer Order Comment, Ecommerce Barcode Search, |
|||
Instagram Feed Snippet, Portal Dashboard, Website Clear Cart, Hide Variants, |
|||
Website Custom Contact Us, Product Attachments on the Website, |
|||
Website Return Order Management and Whatsapp Floating Icon in Website.""", |
|||
'author': 'Cybrosys Techno Solutions', |
|||
'company': 'Cybrosys Techno Solutions', |
|||
'maintainer': 'Cybrosys Techno Solutions', |
|||
'website': "https://www.cybrosys.com", |
|||
'depends': [ |
|||
'base', 'website_sale_wishlist', 'website_sale_comparison', 'stock', |
|||
'sale_management', 'project', 'crm', 'purchase' |
|||
], |
|||
'data': [ |
|||
'security/ir.model.access.csv', |
|||
'data/ir_sequence_data.xml', |
|||
'data/insta_profile_sequence_data.xml', |
|||
'report/sale_return_reports.xml', |
|||
'report/sale_return_templates.xml', |
|||
'views/shop_hide_call_price_templates.xml', |
|||
'views/wishlist_hide_price_templates.xml', |
|||
'views/compare_hide_price_templates.xml', |
|||
'views/call_price_views.xml', |
|||
'views/sale_order_views.xml', |
|||
'views/product_template_views.xml', |
|||
'views/res_config_settings_views.xml', |
|||
'views/customer_order_comment_templates.xml', |
|||
'views/products_barcode_scan_templates.xml', |
|||
'views/portal_dashboard_templates.xml', |
|||
'views/clear_cart_templates.xml', |
|||
'views/website_views.xml', |
|||
'views/website_contact_us_template.xml', |
|||
'views/product_product_views.xml', |
|||
'views/product_attachments_templates.xml', |
|||
'views/website_thankyou_templates.xml', |
|||
'views/sale_return_views.xml', |
|||
'views/sale_return_templates.xml', |
|||
'views/stock_picking_views.xml', |
|||
'views/insta_post_views.xml', |
|||
'views/insta_profile_views.xml', |
|||
'views/sale_order_views.xml', |
|||
'views/carousal_dashboard_templates.xml', |
|||
'views/portal_whatsapp_templates.xml', |
|||
], |
|||
'assets': { |
|||
'web.assets_frontend': [ |
|||
'/all_in_one_website_kit/static/src/js/create_call_price.js', |
|||
'/all_in_one_website_kit/static/src/js/review_and_rating.js', |
|||
'/all_in_one_website_kit/static/src/css/review_and_rating.css', |
|||
'/all_in_one_website_kit/static/src/js/sale_barcode.js', |
|||
'/all_in_one_website_kit/static/src/js/portal_dashboard_graph.js', |
|||
'/all_in_one_website_kit/static/src/js/variants.js', |
|||
'/all_in_one_website_kit/static/src/js/sale_return.js', |
|||
'/all_in_one_website_kit/static/src/js/caroursel.js', |
|||
'https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.9.1/chart.min.js', |
|||
'/all_in_one_website_kit/static/src/scss/style.scss', |
|||
'/all_in_one_website_kit/static/src/js/quagga.js', |
|||
] |
|||
}, |
|||
'external_dependencies': { |
|||
'python': ['pytz', 'geopy'], |
|||
}, |
|||
'images': ['static/description/banner.png'], |
|||
'license': 'AGPL-3', |
|||
'installable': True, |
|||
'auto_install': False, |
|||
'application': False, |
|||
} |
@ -0,0 +1,25 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################### |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: Aysha Shalin (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################### |
|||
from . import all_in_one_website_kit |
|||
from . import main |
|||
from . import portal |
|||
from . import website_sale |
@ -0,0 +1,68 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################### |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: Aysha Shalin (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################### |
|||
import time |
|||
from odoo import http |
|||
from odoo.http import request |
|||
|
|||
|
|||
class WebsiteClearCart(http.Controller): |
|||
""" |
|||
The class WebsiteClearCart is used to clear the cart. |
|||
Methods: |
|||
remove_cart_items(self): |
|||
It will remove all items from cart and redirect to shop page |
|||
""" |
|||
@http.route(['/shop/remove_items'], type="http", auth="public", |
|||
website=True) |
|||
def remove_cart_items(self): |
|||
""" This will remove all items from cart and redirect to shop page """ |
|||
current_orders = request.website.sale_get_order() |
|||
for line in current_orders.website_order_line: |
|||
line.unlink() |
|||
return request.redirect('/shop/cart') |
|||
|
|||
@http.route('/final/customer_rating', type='http', auth="public", |
|||
website=True, sitemap=False) |
|||
def customer_order_rating(self, **kw): |
|||
""" This function helps to fetch the values of comment and rating """ |
|||
order_id = request.env['sale.order'].sudo().browse(int(kw['order_id'])) |
|||
order_id.comment = kw['comment'] |
|||
order_id.rating = kw['rate_value'] |
|||
return request.redirect('/shop/confirmation') |
|||
|
|||
@http.route('/get_dashboard_carousel', auth="public", type='json') |
|||
def get_dashboard_carousel(self): |
|||
""" Getting data to the carousel """ |
|||
events_per_slide = 3 |
|||
records = request.env['insta.post'].sudo().search([]) |
|||
records_grouped = [records[post:post + events_per_slide] for po3333333333333333333333st in |
|||
range(0, len(records), events_per_slide)] |
|||
values = { |
|||
"objects": records_grouped, |
|||
"events_per_slide": events_per_slide, |
|||
"num_slides": len(records_grouped), |
|||
"uniqueId": "pc-%d" % int(time.time() * 1000), |
|||
} |
|||
response = http.Response( |
|||
template='all_in_one_website_kit.s_carousel_template_items', |
|||
qcontext=values) |
|||
return response.render() |
@ -0,0 +1,64 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################### |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: Aysha Shalin (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################### |
|||
from datetime import datetime |
|||
from odoo import http |
|||
from odoo.http import request |
|||
from odoo.addons.website.controllers import main |
|||
|
|||
|
|||
class Home(main.Home): |
|||
""" The CustomerRegistration class is used for creating the sale return |
|||
orders and displaying the thankyou page. """ |
|||
@http.route('/sale_return', type='http', methods=['POST'], |
|||
auth="public", website=True, csrf=False) |
|||
def sale_return(self, **kwargs): |
|||
""" Controller to create return order. """ |
|||
product_id = request.env['product.product'].sudo().browse( |
|||
int(kwargs['product'])) |
|||
order = request.env['sale.order'].sudo().browse(int(kwargs['order_id'])) |
|||
values = { |
|||
'partner_id': order.partner_id.id, |
|||
'order_id': order.id, |
|||
'product_id': product_id.id, |
|||
'quantity': kwargs['qty'], |
|||
'reason': kwargs['reason'], |
|||
'user_id': request.env.uid, |
|||
'create_date': datetime.now(), |
|||
} |
|||
stock_picks = request.env['stock.picking'].search( |
|||
[('origin', '=', order.name)]) |
|||
moves = stock_picks.mapped('move_ids_without_package').filtered( |
|||
lambda p: p.product_id == product_id) |
|||
if moves: |
|||
moves = moves.sorted('product_uom_qty', reverse=True) |
|||
values.update({'state': 'draft'}) |
|||
ret_order = request.env['sale.return'].create(values) |
|||
moves[0].picking_id.return_order_id = ret_order.id |
|||
moves[0].picking_id.return_order_picking = False |
|||
return request.redirect('/my/request-thank-you') |
|||
|
|||
@http.route('/my/request-thank-you', website=True, page=True, |
|||
auth='public', csrf=False) |
|||
def maintenance_request_thanks(self): |
|||
""" Opening thankyou page. """ |
|||
return request.render( |
|||
'all_in_one_website_kit.customers_request_thank_page') |
@ -0,0 +1,415 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################### |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: Aysha Shalin (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################### |
|||
import base64 |
|||
from collections import OrderedDict |
|||
from geopy import Nominatim |
|||
import json |
|||
import pytz |
|||
from odoo import http |
|||
from odoo.exceptions import AccessError, MissingError |
|||
from odoo.http import request, route |
|||
from odoo.tools import image_process |
|||
from odoo.tools.translate import _ |
|||
from odoo.addons.portal.controllers.portal import CustomerPortal |
|||
|
|||
|
|||
class ReturnCustomerPortal(CustomerPortal): |
|||
""" Passing values to the sale return templates. """ |
|||
def _prepare_home_portal_values(self, counters): |
|||
"""getting count of total sale returns""" |
|||
values = super()._prepare_home_portal_values(counters) |
|||
if 'return_count' in counters: |
|||
values['return_count'] = request.env['sale.return'].search_count([ |
|||
('state', 'in', ['draft', 'confirm', 'done', 'cancel'])]) |
|||
return values |
|||
|
|||
@http.route(['/my/return_orders', '/my/return_orders/page/<int:page>'], |
|||
type='http', auth="user", website=True) |
|||
def portal_my_sale_return(self, page=1, date_begin=None, date_end=None, |
|||
sortby=None, filterby=None): |
|||
""" Passing data to the /my/return_orders page. """ |
|||
values = self._prepare_portal_layout_values() |
|||
sale_return = request.env['sale.return'] |
|||
domain = [] |
|||
searchbar_sortings = { |
|||
'date': {'label': _('Newest'), 'order': 'create_date desc'}, |
|||
'name': {'label': _('Name'), 'order': 'name'}, |
|||
'sale': {'label': _('Sale Order'), 'order': 'order_id'}, |
|||
} |
|||
# default sort by value |
|||
if not sortby: |
|||
sortby = 'date' |
|||
order = searchbar_sortings[sortby]['order'] |
|||
if date_begin and date_end: |
|||
domain += [('create_date', '>', date_begin), |
|||
('create_date', '<=', date_end)] |
|||
searchbar_filters = { |
|||
'all': {'label': _('All'), 'domain': [ |
|||
('state', 'in', ['draft', 'confirm', 'done', 'cancel'])]}, |
|||
'confirm': {'label': _('Confirmed'), |
|||
'domain': [('state', '=', 'confirm')]}, |
|||
'cancel': {'label': _('Cancelled'), |
|||
'domain': [('state', '=', 'cancel')]}, |
|||
'done': {'label': _('Done'), 'domain': [('state', '=', 'done')]}, |
|||
} |
|||
# default filter by value |
|||
if not filterby: |
|||
filterby = 'all' |
|||
domain += searchbar_filters[filterby]['domain'] |
|||
# pager |
|||
pager = request.website.pager( |
|||
url="/my/return_orders", |
|||
url_args={'date_begin': date_begin, 'date_end': date_end, |
|||
'sortby': sortby}, |
|||
total=sale_return.search_count(domain), |
|||
page=page, |
|||
step=self._items_per_page |
|||
) |
|||
# content according to pager and archive selected |
|||
orders = sale_return.search(domain, order=order, |
|||
limit=self._items_per_page, |
|||
offset=pager['offset']) |
|||
request.session['my_return_history'] = orders.ids[:100] |
|||
values.update({ |
|||
'date': date_begin, |
|||
'orders': orders.sudo(), |
|||
'page_name': 'Sale_Return', |
|||
'default_url': '/my/return_orders', |
|||
'pager': pager, |
|||
'searchbar_filters': OrderedDict(sorted(searchbar_filters.items())), |
|||
'searchbar_sortings': searchbar_sortings, |
|||
'sortby': sortby, |
|||
}) |
|||
return request.render("all_in_one_website_kit.portal_my_returns", |
|||
values) |
|||
|
|||
@http.route(['/my/return_orders/<int:order_id>'], type='http', |
|||
auth="public", website=True) |
|||
def portal_my_return_detail(self, order_id=None, access_token=None, |
|||
report_type=None, download=False, **kw): |
|||
""" Passing data to individual return orders. """ |
|||
try: |
|||
order_sudo = self._document_check_access('sale.return', order_id, |
|||
access_token) |
|||
except (AccessError, MissingError): |
|||
return request.redirect('/my') |
|||
if report_type in ('html', 'pdf', 'text'): |
|||
return self._show_report( |
|||
model=order_sudo, report_type=report_type, |
|||
report_ref='all_in_one_website_kit.report_sale_returns', |
|||
download=download) |
|||
values = self._sale_return_get_page_view_values(order_sudo, |
|||
access_token, **kw) |
|||
return request.render("all_in_one_website_kit.portal_sale_return_page", |
|||
values) |
|||
|
|||
def _sale_return_get_page_view_values(self, order, access_token, **kwargs): |
|||
""" Getting values to the function portal_my_return_detail. """ |
|||
def resize_to_48(b64source): |
|||
if not b64source: |
|||
b64source = request.env['ir.binary']._placeholder() |
|||
else: |
|||
b64source = base64.b64decode(b64source) |
|||
return base64.b64encode(image_process(b64source, size=(48, 48))) |
|||
|
|||
values = { |
|||
'orders': order, |
|||
'resize_to_48': resize_to_48, |
|||
} |
|||
return self._get_page_view_values(order, access_token, values, |
|||
'my_return_history', False, **kwargs) |
|||
|
|||
@route(['/my', '/my/home'], type='http', auth="user", website=True) |
|||
def home(self, **kw): |
|||
""" Replaces already existing work flow of portal view to redirect to |
|||
new template with record values and count. """ |
|||
user = request.env.user.id |
|||
partners = request.env.user |
|||
group_id = request.env.ref('base.group_user') |
|||
order_id = request.env['sale.order'].sudo() |
|||
purchase_order = request.env['purchase.order'].sudo() |
|||
account_move = request.env['account.move'] |
|||
project = request.env['project.project'].sudo() |
|||
task = request.env['project.task'].sudo() |
|||
config_parameters = request.env['ir.config_parameter'].sudo() |
|||
number_project = "" |
|||
projects_limited = "" |
|||
tasks_limited = "" |
|||
number_account = "" |
|||
invoices_limited = "" |
|||
show_project = request.env[ |
|||
'ir.config_parameter' |
|||
].sudo().get_param('all_in_one_website_kit.is_show_project') |
|||
show_account = request.env['ir.config_parameter'].sudo().get_param( |
|||
'all_in_one_website_kit.is_show_recent_invoice_bill') |
|||
show_so_q = request.env['ir.config_parameter'].sudo().get_param( |
|||
'all_in_one_website_kit.is_show_recent_so_q') |
|||
show_po_rfq = request.env[ |
|||
'ir.config_parameter' |
|||
].sudo().get_param('all_in_one_website_kit.is_show_recent_po_rfq') |
|||
number_order = "" |
|||
sale_orders_limited = "" |
|||
quotations_limited = "" |
|||
number_po = "" |
|||
purchase_orders_limited = "" |
|||
rfq_limited = "" |
|||
if group_id in partners.groups_id: |
|||
if show_so_q: |
|||
number_order = request.env[ |
|||
'ir.config_parameter' |
|||
].sudo().get_param('all_in_one_website_kit.sale_count', 0) |
|||
sale_orders_limited = order_id.search([ |
|||
'|', ('user_id', '=', user), |
|||
('partner_id', '=', request.env.user.partner_id.id), |
|||
('state', 'not in', ['draft', 'sent']) |
|||
], limit=int(number_order)) |
|||
quotations_limited = order_id.search([ |
|||
'|', ('user_id', '=', user), |
|||
('partner_id', '=', request.env.user.partner_id.id), |
|||
('state', 'in', ['sent']) |
|||
], limit=int(number_order)) |
|||
if show_po_rfq: |
|||
number_po = config_parameters.get_param( |
|||
'all_in_one_website_kit.purchase_count', 0) |
|||
purchase_orders_limited = purchase_order.search([ |
|||
'|', ('user_id', '=', user), |
|||
('partner_id', '=', request.env.user.partner_id.id), |
|||
('state', 'not in', ['draft', 'sent', 'to approve']) |
|||
], limit=int(number_po)) |
|||
rfq_limited = purchase_order.search([ |
|||
'|', ('user_id', '=', user), |
|||
('partner_id', '=', request.env.user.partner_id.id), |
|||
('state', 'in', ['draft', 'sent', 'to approve']) |
|||
], limit=int(number_po)) |
|||
if show_project: |
|||
number_project = config_parameters.get_param( |
|||
'all_in_one_website_kit.project_count', 0) |
|||
projects_limited = project.search([], |
|||
limit=int(number_project)) |
|||
tasks_limited = task.search([], limit=int(number_project)) |
|||
if show_account: |
|||
number_account = config_parameters.get_param( |
|||
'all_in_one_website_kit.account_count', 0) |
|||
invoices_limited = account_move.search([ |
|||
('partner_id', '=', user.partner_id.id), |
|||
('state', 'not in', ['draft', 'cancel']) |
|||
], limit=int(number_account)) |
|||
sale_orders = order_id.search([ |
|||
'|', ('user_id', '=', user), |
|||
('partner_id', '=', request.env.user.partner_id.id), |
|||
('access_token', '!=', False), |
|||
('state', 'not in', ['draft', 'sent']) |
|||
]) |
|||
quotations = request.env['sale.order'].sudo().search([ |
|||
'|', ('user_id', '=', user), |
|||
('partner_id', '=', request.env.user.partner_id.id), |
|||
('state', '=', 'sent') |
|||
]) |
|||
purchase_orders = purchase_order.search([ |
|||
'|', ('user_id', '=', user), |
|||
('partner_id', '=', request.env.user.partner_id.id), |
|||
('state', 'not in', ['draft', 'sent', 'to approve']) |
|||
]) |
|||
rfq = purchase_order.search([ |
|||
'|', ('user_id', '=', user), |
|||
('partner_id', '=', request.env.user.partner_id.id), |
|||
('state', '=', 'sent') |
|||
]) |
|||
projects = project.search([]) |
|||
tasks = task.search([]) |
|||
invoices = account_move.search([('access_token', '!=', False)]) |
|||
else: |
|||
if show_so_q: |
|||
number_order = config_parameters.get_param( |
|||
'all_in_one_website_kit.sale_count', 0) |
|||
sale_orders_limited = order_id.search([ |
|||
('partner_id', '=', partners.partner_id.id), |
|||
('state', 'not in', ['draft', 'sent']) |
|||
], limit=int(number_order)) |
|||
quotations_limited = order_id.search([ |
|||
('partner_id', '=', partners.partner_id.id), |
|||
('state', 'in', ['sent']) |
|||
], limit=int(number_order)) |
|||
if show_po_rfq: |
|||
number_po = config_parameters.get_param( |
|||
'all_in_one_website_kit.purchase_count', 0) |
|||
purchase_orders_limited = purchase_order.search([ |
|||
('partner_id', '=', partners.partner_id.id), |
|||
('state', 'not in', ['draft', 'sent', 'to approve']) |
|||
], limit=int(number_po)) |
|||
rfq_limited = purchase_order.search([ |
|||
('partner_id', '=', partners.partner_id.id), |
|||
('state', 'in', ['draft', 'sent', 'to approve']) |
|||
], limit=int(number_po)) |
|||
if show_project: |
|||
number_project = config_parameters.get_param( |
|||
'all_in_one_website_kit.project_count', 0) |
|||
projects_limited = project.search([('user_id', '=', user)], |
|||
limit=int(number_project)) |
|||
tasks_limited = task.search([('user_id', '=', user)], |
|||
limit=int(number_project)) |
|||
if show_account: |
|||
number_account = config_parameters.get_param( |
|||
'all_in_one_website_kit.account_count', 0) |
|||
invoices_limited = account_move.search([ |
|||
('partner_id', '=', partners.partner_id.id), |
|||
('state', 'not in', ['draft', 'cancel']) |
|||
], limit=int(number_account)) |
|||
sale_orders = order_id.search([ |
|||
'|', ('user_id', '=', user), |
|||
('partner_id', '=', partners.partner_id.id), |
|||
('state', 'not in', ['draft', 'sent']) |
|||
]) |
|||
quotations = order_id.search([ |
|||
'|', ('user_id', '=', user), |
|||
('partner_id', '=', partners.partner_id.id), |
|||
('state', 'in', ['sent']) |
|||
]) |
|||
purchase_orders = purchase_order.search([ |
|||
'|', ('user_id', '=', user), |
|||
('partner_id', '=', partners.partner_id.id), |
|||
('state', 'not in', ['draft', 'sent', 'to approve']) |
|||
]) |
|||
rfq = purchase_order.search([ |
|||
'|', ('user_id', '=', user), |
|||
('partner_id', '=', partners.partner_id.id), |
|||
('state', 'in', ['sent', 'to approve']) |
|||
]) |
|||
projects = project.search([ |
|||
('user_id', '=', user) |
|||
]) |
|||
tasks = task.search([('user_id', '=', user)]) |
|||
invoices = account_move.search([ |
|||
('access_token', '!=', False) |
|||
]) |
|||
values = self._prepare_portal_layout_values() |
|||
values['sale_order_portal'] = sale_orders |
|||
values['quotation_portal'] = quotations |
|||
values['counts_quotation'] = len(quotations) |
|||
values['purchase_orders_portal'] = purchase_orders |
|||
values['rfq_portal'] = rfq |
|||
values['projects_portal'] = projects |
|||
values['tasks_portal'] = tasks |
|||
values['invoices_portal'] = invoices |
|||
values['number_so_portal'] = number_order |
|||
values['number_po_portal'] = number_po |
|||
values['number_account_portal'] = number_account |
|||
values['number_project_portal'] = number_project |
|||
values['sale_orders_limited'] = sale_orders_limited |
|||
values['quotations_limited'] = quotations_limited |
|||
values['purchase_orders_limited'] = purchase_orders_limited |
|||
values['rfq_limited'] = rfq_limited |
|||
values['invoices_limited'] = invoices_limited |
|||
values['projects_limited'] = projects_limited |
|||
values['tasks_limited'] = tasks_limited |
|||
values['show_so_q'] = show_so_q |
|||
values['show_po_rfq'] = show_po_rfq |
|||
values['show_project'] = show_project |
|||
values['show_account'] = show_account |
|||
values['count_return_order'] = request.env['sale.return'].search_count( |
|||
[('user_id', '=', request.env.uid)]) |
|||
return request.render( |
|||
"all_in_one_website_kit.portal_dashboard_data", |
|||
values) |
|||
|
|||
@route() |
|||
def account(self, **post): |
|||
""" Super CustomerPortal class function and pass the api key value |
|||
from settings using params to website view file. """ |
|||
res = super(ReturnCustomerPortal, self).account(**post) |
|||
params = request.env['ir.config_parameter'].sudo() |
|||
values = params.get_param('base_geolocalize.google_map_api_key') |
|||
res.qcontext.update({ |
|||
'api': values |
|||
}) |
|||
return res |
|||
|
|||
@http.route(['/geo/change/<coordinates>'], type='json', auth="none", |
|||
website=False, csrf=False) |
|||
def geo_changer(self, coordinates): |
|||
""" Controller function for get address details from latitude and |
|||
longitude that we pinpointed in map using geopy package from python |
|||
|
|||
Parameters ---------- coordinates :The stringify value from map that |
|||
contains latitude and longitude |
|||
|
|||
Returns ------- Returning the address details back to view file from |
|||
the converted Latitude and longitude |
|||
""" |
|||
res = json.loads(coordinates) |
|||
geolocator = Nominatim(user_agent="geoapiExercises") |
|||
location = geolocator.reverse( |
|||
str(res.get('lat')) + "," + str(res.get('lng'))) |
|||
city = "Undefined" |
|||
suburb = "Undefined" |
|||
state = "Undefined" |
|||
country = "Undefined" |
|||
p_code = "Undefined" |
|||
if location: |
|||
addresses = location.raw['address'] |
|||
if addresses.get('village'): |
|||
city = addresses.get('village') |
|||
if addresses.get('suburb'): |
|||
suburb = addresses.get('suburb') |
|||
state = addresses.get('state') |
|||
country_code = addresses.get('country_code') |
|||
country = pytz.country_names[country_code] |
|||
if addresses.get('postcode'): |
|||
p_code = addresses.get('postcode') |
|||
return { |
|||
'city': city, |
|||
'suburb': suburb, |
|||
'state': state, |
|||
'country': country, |
|||
'p_code': p_code, |
|||
} |
|||
|
|||
@http.route(['/geo/location/<address>'], type='json', auth="none", |
|||
website=False, csrf=False) |
|||
def geo_location(self, address): |
|||
""" Get value from city field in 'my_account' page and convert into |
|||
lat and long and return back to website and set the map and fields |
|||
Parameters ---------- address : The city name that in city field in |
|||
website |
|||
|
|||
Returns |
|||
------- |
|||
Pass the value to website view and set required fields and map |
|||
|
|||
""" |
|||
locator = Nominatim(user_agent="myGeocoder") |
|||
location = locator.geocode(address) |
|||
geolocator = Nominatim(user_agent="geoapiExercises") |
|||
location_country = geolocator.reverse( |
|||
str(location.latitude) + "," + str(location.longitude)) |
|||
addresses = location_country.raw['address'] |
|||
country_code = addresses.get('country_code') |
|||
country = pytz.country_names[country_code] |
|||
p_code = "undefined" |
|||
if addresses.get('postcode'): |
|||
p_code = addresses.get('postcode') |
|||
return { |
|||
'lat': location.latitude, |
|||
'lng': location.longitude, |
|||
'country': country, |
|||
'p_code': p_code |
|||
} |
@ -0,0 +1,95 @@ |
|||
# -*- coding: utf-8 -*- |
|||
################################################################################ |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
|||
# Author: Aysha Shalin (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
################################################################################ |
|||
import base64 |
|||
import io |
|||
from werkzeug.utils import redirect |
|||
from odoo import http |
|||
from odoo.http import request |
|||
from odoo.addons.http_routing.models.ir_http import slug |
|||
from odoo.addons.website_sale.controllers.main import WebsiteSale |
|||
|
|||
|
|||
class WebsiteSale(WebsiteSale): |
|||
""" The class WebsiteProductBarcode is used for getting product with scanned |
|||
barcode. """ |
|||
@http.route([ |
|||
'/shop/barcodeproduct'], type='json', auth="user", website=True, |
|||
methods=['GET', 'POST']) |
|||
def product_barcode(self, **kwargs): |
|||
""" checking the is scanned or not and passes the corresponding |
|||
values""" |
|||
barcode_product = request.env['product.product'].search( |
|||
[('barcode', '=', kwargs.get('last_code'))]) |
|||
if barcode_product: |
|||
return { |
|||
'type': 'ir.actions.act_url', |
|||
'url': '/shop/%s' % slug(barcode_product.product_tmpl_id) |
|||
} |
|||
else: |
|||
return False |
|||
|
|||
@http.route(['/shop/<model("product.template"):product>'], type='http', |
|||
auth="public", website=True) |
|||
def product(self, product, category='', search='', **kwargs): |
|||
""" Supering the controller to pass the values. """ |
|||
res = super(WebsiteSale, self).product(product, category='', search='', |
|||
**kwargs) |
|||
res.qcontext['attachments'] = request.env[ |
|||
'ir.attachment'].sudo().search( |
|||
[('res_model', '=', 'product.template'), |
|||
('res_id', '=', product.id)], order='id') |
|||
return res |
|||
|
|||
def _get_attribute_exclusion(self, product, reference_product=None): |
|||
""" Check the product variant. """ |
|||
parent_combination = request.env['product.template.attribute.value'] |
|||
if reference_product: |
|||
parent_combination |= reference_product.product_template_attribute_value_ids |
|||
if reference_product.env.context.get('no_variant_attribute_values'): |
|||
# Add "no_variant" attribute values' exclusions |
|||
# They are kept in the context since they are not linked to this |
|||
# product variant |
|||
parent_combination |= reference_product.env.context.get( |
|||
'no_variant_attribute_values') |
|||
return product._get_attribute_exclusions(parent_combination) |
|||
|
|||
@http.route(['/attachment/download', ], type='http', auth='public') |
|||
def download_attachment(self, attachment_id): |
|||
""" To download the document of the product. """ |
|||
# Check if this is a valid attachment id |
|||
attachment = request.env['ir.attachment'].sudo().browse( |
|||
int(attachment_id)) |
|||
if attachment: |
|||
attachment = attachment[0] |
|||
else: |
|||
return redirect('/shop') |
|||
if attachment["type"] == "url": |
|||
if attachment["url"]: |
|||
return redirect(attachment["url"]) |
|||
else: |
|||
return request.not_found() |
|||
elif attachment["datas"]: |
|||
data = io.BytesIO(base64.standard_b64decode(attachment["datas"])) |
|||
return http.send_file(data, filename=attachment['name'], |
|||
as_attachment=True) |
|||
else: |
|||
return request.not_found() |
@ -0,0 +1,11 @@ |
|||
<?xml version="1.0" encoding="utf-8" ?> |
|||
<odoo> |
|||
<data noupdate="1"> |
|||
<record id="insta_profile_id" model="ir.sequence"> |
|||
<field name="name">Profile ID</field> |
|||
<field name="code">insta.profile</field> |
|||
<field name="prefix">INST</field> |
|||
<field name="padding">2</field> |
|||
</record> |
|||
</data> |
|||
</odoo> |
@ -0,0 +1,13 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<odoo> |
|||
<data noupdate="1"> |
|||
<!-- Sequence for sale return --> |
|||
<record id="sale_return_ir_sequence" model="ir.sequence"> |
|||
<field name="name">Sale Return</field> |
|||
<field name="code">sale.return</field> |
|||
<field name="prefix">RET</field> |
|||
<field name="padding">5</field> |
|||
<field name="company_id" eval="False"/> |
|||
</record> |
|||
</data> |
|||
</odoo> |
@ -0,0 +1,6 @@ |
|||
## Module <all_in_one_website_kit> |
|||
|
|||
#### 03.09.2024 |
|||
#### Version 15.0.1.0.0 |
|||
##### ADD |
|||
- Initial Commit for All In One Website Kit |
@ -0,0 +1,33 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################### |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: Aysha Shalin (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################### |
|||
from . import call_price |
|||
from . import insta_post |
|||
from . import insta_profile |
|||
from . import portal_dashboard_data |
|||
from . import product_product |
|||
from . import product_template |
|||
from . import res_config_settings |
|||
from . import sale_order |
|||
from . import sale_return |
|||
from . import stock_picking |
|||
from . import stock_return_picking |
|||
from . import website |
@ -0,0 +1,67 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################### |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: Aysha Shalin (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################### |
|||
from odoo import api, fields, models |
|||
|
|||
|
|||
class CallPrice(models.Model): |
|||
""" Creating a model to record all the request for price from website. """ |
|||
_name = 'call.price' |
|||
_description = 'Call for Price' |
|||
_rec_name = 'product_id' |
|||
|
|||
first_name = fields.Char(string="First Name", help="First Name of user") |
|||
last_name = fields.Char(string="Last Name", help="Last Name of user") |
|||
product_id = fields.Many2one('product.template', string="Product", |
|||
help="In which product " |
|||
"they are requesting price") |
|||
email = fields.Char(string="Email", help="Users email for contact") |
|||
phone = fields.Char(string="Contact No.", |
|||
help="Users contact number for contacting") |
|||
quantity = fields.Float(string="Quantity", |
|||
help="How much quantity of product price " |
|||
"they want know") |
|||
message = fields.Char(string="Message", |
|||
help="If any messages for referring") |
|||
state = fields.Selection( |
|||
[('draft', 'Draft'), ('done', 'Done'), ('cancel', 'Cancel')], |
|||
default="draft", help="Call for price requests stage", string="State") |
|||
|
|||
def action_done(self): |
|||
""" Change state of the form to 'done'. """ |
|||
self.write({'state': 'done'}) |
|||
|
|||
def action_cancel(self): |
|||
""" Cancel the form and change the state to cancel. """ |
|||
self.write({'state': 'cancel'}) |
|||
|
|||
@api.model |
|||
def create_form(self, first, last, product_id, phone, email, message, qty): |
|||
""" Create the request from the users in the backend. """ |
|||
self.create({ |
|||
'product_id': product_id, |
|||
'first_name': first, |
|||
'last_name': last, |
|||
'phone': phone, |
|||
'email': email, |
|||
'quantity': qty, |
|||
'message': message |
|||
}) |
@ -0,0 +1,57 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################### |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: Aysha Shalin (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################### |
|||
import requests |
|||
from odoo import _, fields, models |
|||
from odoo.exceptions import UserError |
|||
|
|||
|
|||
class InstaPost(models.Model): |
|||
""" In the class InstaPost getting the posts of corresponding selected |
|||
instagram account. """ |
|||
_name = 'insta.post' |
|||
_description = 'Insta Post' |
|||
|
|||
name = fields.Char(string="Media ID", help="The field defines Media ID") |
|||
caption = fields.Char(string="Caption", |
|||
help="This field defines the caption") |
|||
post_image = fields.Binary(string='Post Image', attachment=True, |
|||
help="The field is defined for attaching the" |
|||
"post image") |
|||
profile_id = fields.Many2one('insta.profile', |
|||
string="Profile ID", |
|||
help="The field defines the insta profile id") |
|||
|
|||
def action_update_post(self, access_token): |
|||
""" Action for updating the posts """ |
|||
url = ('https://graph.facebook.com/v15.0/%s?fields=id,caption,' + |
|||
'comments_count,is_comment_enabled,like_count,' + |
|||
'media_product_type,media_type,media_url,owner,permalink,' + |
|||
'thumbnail_url,timestamp,username&access_token=%s') % ( |
|||
self.name, access_token) |
|||
media_content = requests.get(url, timeout=5).json() |
|||
if not media_content.get('error'): |
|||
if media_content.get('caption'): |
|||
self.write({ |
|||
'caption': media_content['caption'], |
|||
}) |
|||
else: |
|||
raise UserError(_('%s', media_content['error']['message'])) |
@ -0,0 +1,119 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################### |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: Aysha Shalin (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################### |
|||
import base64 |
|||
import requests |
|||
from odoo import _, api, fields, models |
|||
from odoo.exceptions import UserError |
|||
|
|||
|
|||
class InstaProfile(models.Model): |
|||
"""class for adding instagram account""" |
|||
_name = 'insta.profile' |
|||
_description = 'Insta Profile' |
|||
|
|||
name = fields.Char(string="Name", readonly=True, |
|||
help="The name for the insta profile.") |
|||
access_token = fields.Char(string="Access Token", required=True, |
|||
help="The Access Token for the insta profile.") |
|||
username = fields.Char(string='Username', readonly=True, |
|||
help="The field defines the user name") |
|||
account_id = fields.Char(string='Account ID', readonly=True, |
|||
help="The field defines the Account id for the" |
|||
" insta profile") |
|||
profile_image_url = fields.Binary(attachment=True, string="Profile Image", |
|||
help="The profile image can upload here.") |
|||
|
|||
@api.model |
|||
def create(self, vals): |
|||
"""" To generate sequence for instagram profiles """ |
|||
if vals.get('name', 'New') == 'New': |
|||
vals['name'] = self.env['ir.sequence'].next_by_code( |
|||
'insta.profile') or 'New' |
|||
result = super(InstaProfile, self).create(vals) |
|||
return result |
|||
|
|||
def action_fetch(self): |
|||
""" The action is to check the accounts with the given |
|||
access token """ |
|||
url = ('https://graph.facebook.com/v15.0/me/accounts?access_token=%s' |
|||
% self.access_token) |
|||
page = requests.get(url) |
|||
page_content = page.json() |
|||
if not page_content.get('error'): |
|||
if page_content['data'][0]['id']: |
|||
url = 'https://graph.facebook.com/v14.0/%s?fields=instagram_business_account&access_token=%s' % ( |
|||
page_content['data'][0]['id'], self.access_token) |
|||
business_account = requests.get(url) |
|||
instagram_business_account = \ |
|||
business_account.json()['instagram_business_account']['id'] |
|||
url = ('https://graph.facebook.com/v15.0/%s?fields=name,username,biography,website,followers_count,follows_count,media_count,profile_picture_url&access_token=%s' |
|||
% (instagram_business_account, self.access_token)) |
|||
val = requests.get(url) |
|||
content = val.json() |
|||
if content.get('name'): |
|||
self.name = content['name'] |
|||
if content.get('username'): |
|||
self.username = content['username'] |
|||
if content.get('id'): |
|||
self.account_id = content['id'] |
|||
if content.get('profile_picture_url'): |
|||
img = base64.b64encode( |
|||
requests.get(content['profile_picture_url']).content) |
|||
self.profile_image_url = img |
|||
else: |
|||
raise UserError(_('%s', page_content['error']['message'])) |
|||
|
|||
def action_get_post(self): |
|||
""" For getting and write posts to insta post model """ |
|||
url = 'https://graph.facebook.com/v15.0/%s/media?access_token=%s' % ( |
|||
self.account_id, self.access_token) |
|||
content = requests.get(url, timeout=5).json() |
|||
if not content.get('error'): |
|||
post_list = [post.name for post in |
|||
self.env['insta.post'].search([])] |
|||
if content.get('data'): |
|||
for vals in content['data']: |
|||
if vals['id'] not in post_list: |
|||
url = 'https://graph.facebook.com/v14.0/%s?fields=id,caption,comments_count,is_comment_enabled,like_count,media_product_type,media_type,media_url,owner,permalink,thumbnail_url,timestamp,username&access_token=%s' % ( |
|||
vals['id'], self.access_token) |
|||
media_content = requests.get(url, timeout=5).json() |
|||
if media_content.get('media_type'): |
|||
if media_content['media_type'] == 'IMAGE': |
|||
res = self.env['insta.post'].create({ |
|||
'name': media_content['id'], |
|||
'profile_id': self.id, |
|||
}) |
|||
image_data = base64.b64encode(requests.get( |
|||
media_content['media_url']).content) |
|||
res.write({ |
|||
'post_image': image_data, |
|||
}) |
|||
if media_content.get('caption'): |
|||
res.write({ |
|||
'caption': media_content['caption'], |
|||
}) |
|||
else: |
|||
record = self.env['insta.post'].search( |
|||
[('name', '=', vals['id'])]) |
|||
record.action_update_post(self.access_token) |
|||
else: |
|||
raise UserError(_('%s', content['error']['message'])) |
@ -0,0 +1,61 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################### |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: Aysha Shalin (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################### |
|||
from odoo import api, models |
|||
|
|||
|
|||
class PortalDashboardData(models.Model): |
|||
""" Used to set graphs in portal dashboard template """ |
|||
_name = 'portal.dashboard.data' |
|||
_description = 'Portal Dashboard Data' |
|||
|
|||
@api.model |
|||
def datafetch(self): |
|||
""" To fetch data of backend documents to display in the portal |
|||
dashboard depending on count of records. """ |
|||
user = self.env.user |
|||
group_id = self.env.ref('base.group_user') |
|||
if group_id in user.groups_id: |
|||
all_invoice = self.env['account.move'].search_count([ |
|||
('state', 'not in', ['draft', 'cancel']), |
|||
('partner_id', '=', user.partner_id.id)]) |
|||
all_accounting = [all_invoice] |
|||
else: |
|||
all_invoice = self.env['account.move'].search_count([ |
|||
('partner_id', '=', user.partner_id.id), |
|||
('state', 'not in', ['draft', 'cancel'])]) |
|||
all_accounting = [all_invoice] |
|||
order_id = self.env['sale.order'].search_count([ |
|||
('user_id', '=', user.id), |
|||
('state', 'not in', ['draft', 'sent'])]) |
|||
quotations = self.env['sale.order'].search_count([ |
|||
('user_id', '=', user.id), ('state', 'in', ['sent'])]) |
|||
purchase_order = self.env['purchase.order'].search_count([ |
|||
('user_id', '=', user.id), |
|||
('state', 'not in', ['draft', 'sent', 'to approve'])]) |
|||
purchase_rfq = self.env['purchase.order'].search_count([ |
|||
('user_id', '=', user.id), |
|||
('state', 'in', ['sent', 'to approve'])]) |
|||
return { |
|||
'target': [order_id, quotations], |
|||
'target_po': [purchase_order, purchase_rfq], |
|||
'target_accounting': all_accounting |
|||
} |
@ -0,0 +1,32 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################### |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: Aysha Shalin (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################### |
|||
from odoo import fields, models |
|||
|
|||
|
|||
class ProductProduct(models.Model): |
|||
""" Field to hide the product variants in website """ |
|||
_inherit = 'product.product' |
|||
|
|||
website_hide_variants = fields.Boolean(string="Hide on Website", |
|||
help="Check right if you want to " |
|||
"hide the variant in your " |
|||
"website") |
@ -0,0 +1,33 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################### |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: Aysha Shalin (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################### |
|||
from odoo import fields, models |
|||
|
|||
|
|||
class ProductTemplate(models.Model): |
|||
""" Inheriting product template model for adding a field that will hide |
|||
price from website. """ |
|||
_inherit = 'product.template' |
|||
|
|||
price_call = fields.Boolean(string="Call for Price", |
|||
help="This will hide the price and cart button" |
|||
" from shop and customer can request by " |
|||
"calling for price") |
@ -0,0 +1,66 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################### |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: Aysha Shalin (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################### |
|||
from odoo import fields, models |
|||
|
|||
|
|||
class ResConfigSettings(models.TransientModel): |
|||
""" Inherits res.config.settings to add new setting for enabling cusomer |
|||
ratings and displaying records in portal. """ |
|||
_inherit = 'res.config.settings' |
|||
|
|||
comment_configuration = fields.Boolean( |
|||
config_parameter='all_in_one_website_kit.comment_configuration', |
|||
string='Comment Configuration', help='Enable/ Disable the feature.') |
|||
is_show_recent_so_q = fields.Boolean( |
|||
string='Is show recent quotation and sale order table', |
|||
config_parameter='all_in_one_website_kit.is_show_recent_so_q', |
|||
help="Enable the field for show the recent quotation and" |
|||
"sale order table ") |
|||
sale_count = fields.Integer( |
|||
string='How many recent records do you want to show?', |
|||
config_parameter='all_in_one_website_kit.sale_count', |
|||
help="The field shows the number of recent records want to show") |
|||
is_show_recent_po_rfq = fields.Boolean( |
|||
string='Is show recent RFQ table?', |
|||
config_parameter='all_in_one_website_kit.is_show_recent_po_rfq', |
|||
help="Enable the field to show the recent RFQ table.") |
|||
purchase_count = fields.Integer( |
|||
string='How many recent records do you want to show?', |
|||
config_parameter='all_in_one_website_kit.purchase_count', |
|||
help="The field shows the number of purchase records want to show.") |
|||
is_show_project = fields.Boolean( |
|||
string='Is show project task table?', |
|||
config_parameter='all_in_one_website_kit.is_show_project', |
|||
help="Enable the field to show the project task table.") |
|||
project_count = fields.Integer( |
|||
string='How many recent records do you want to show?', |
|||
config_parameter='all_in_one_website_kit.project_count', |
|||
help="The field shows the recent project records want to show.") |
|||
is_show_recent_invoice_bill = fields.Boolean( |
|||
string='Is show recent invoice/bill table?', |
|||
config_parameter='all_in_one_website_kit.is_show_recent_invoice_bill', |
|||
help="Enable the field to show the recent invoice/bill.") |
|||
account_count = fields.Integer( |
|||
string='How many recent records do you want to show?', |
|||
config_parameter='all_in_one_website_kit.account_count', |
|||
help="The field shows the number of recent invoice/bill records" |
|||
"want to show.") |
@ -0,0 +1,60 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################### |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: Aysha Shalin (odoo@cybrosys.com>) |
|||
# |
|||
# You can modify it under the terms of the GNU LESSER |
|||
# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE |
|||
# (LGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################### |
|||
from odoo import fields, models |
|||
|
|||
|
|||
class SaleOrder(models.Model): |
|||
""" Inherits sale order to add the fields comment and rating """ |
|||
_inherit = 'sale.order' |
|||
|
|||
comment = fields.Char(string='Comment', readonly=True, |
|||
help='The comment provided by the customer.') |
|||
rating = fields.Selection([ |
|||
('1', 'Poor'), ('2', 'Too Bad'), ('3', 'Average Quality'), |
|||
('4', 'Nice'), ('5', 'Good')], string='Rating', readonly=True, |
|||
help='The rating provided by the customer.') |
|||
return_order_count = fields.Integer(compute="_compute_return_order_count", |
|||
string='Return Orders') |
|||
|
|||
def _compute_return_order_count(self): |
|||
""" Method to compute return count """ |
|||
sale_return_groups = self.env['sale.return'].sudo().read_group( |
|||
domain=[('order_id', '=', self.ids)], |
|||
fields=['order_id'], groupby=['order_id']) |
|||
orders = self.browse() |
|||
for group in sale_return_groups: |
|||
order_id = self.browse(group['order_id'][0]) |
|||
while order_id: |
|||
if order_id in self: |
|||
order_id.return_order_count += group['order_id_count'] |
|||
orders |= order_id |
|||
order_id = False |
|||
(self - orders).return_order_count = 0 |
|||
|
|||
def action_open_returns(self): |
|||
""" This function returns an action that displays the return orders |
|||
from sale order. """ |
|||
action = self.env['ir.actions.act_window']._for_xml_id( |
|||
'all_in_one_website_kit.sale_return_action') |
|||
action['domain'] = [('order_id', '=', self.id)] |
|||
action['context'] = {'search_default_order': 1} |
|||
return action |
@ -0,0 +1,264 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################### |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: Aysha Shalin (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################### |
|||
from odoo import api, fields, models |
|||
|
|||
|
|||
class SaleReturn(models.Model): |
|||
""" Return of Sale Orders """ |
|||
_name = 'sale.return' |
|||
_description = "Return Order" |
|||
_inherit = ['portal.mixin'] |
|||
_rec_name = "name" |
|||
_order = "name" |
|||
|
|||
@api.model |
|||
def _get_default_name(self): |
|||
""" Returns the default name to the sale return """ |
|||
return self.env['ir.sequence'].get('sale.return') |
|||
|
|||
active = fields.Boolean(string='Active', default=True, |
|||
help="Enable the field to active the record") |
|||
name = fields.Char(string="Name", default=_get_default_name, |
|||
help="The field returns the sequence number of " |
|||
"sales return.") |
|||
product_id = fields.Many2one('product.product', string="Product Variant", |
|||
required=True, |
|||
help="Defines the product variant that need to" |
|||
" be returned") |
|||
product_tmpl_id = fields.Many2one('product.template', |
|||
related="product_id.product_tmpl_id", |
|||
store=True, string="Product", |
|||
help="Defines the product") |
|||
order_id = fields.Many2one('sale.order', string="Sale Order", required=True, |
|||
help="The field refer the sale order ") |
|||
partner_id = fields.Many2one('res.partner', string="Customer", |
|||
help="The field refer the partner") |
|||
user_id = fields.Many2one('res.users', string="Responsible", |
|||
default=lambda self: self.env.user, |
|||
help="The field refer the user.") |
|||
create_date = fields.Datetime(string="Create Date", |
|||
help="The field shows the create date.") |
|||
quantity = fields.Float(string="Quantity", default=0, |
|||
help='The field refer the quantity') |
|||
received_qty = fields.Float(string="Received Quantity", |
|||
help="The field refer the received quantity") |
|||
reason = fields.Text(string="Reason", |
|||
help="The field defines reason for the sale return") |
|||
stock_picking_ids = fields.One2many('stock.picking', |
|||
'return_order_pick_id', |
|||
domain="[('return_order_id','=',False)]", |
|||
string="Return Picking", |
|||
help="Shows the return picking of the " |
|||
"corresponding return order") |
|||
picking_count = fields.Integer(compute="_compute_delivery_picking_count", |
|||
string='Picking Order', copy=False, |
|||
default=0, store=True, |
|||
help="Field compute the count of picking") |
|||
delivery_count = fields.Integer(compute="_compute_delivery_picking_count", |
|||
string='Delivery Order', copy=False, |
|||
default=0, store=True, |
|||
help="Field compute the count of delivery") |
|||
state = fields.Selection( |
|||
[('draft', 'Draft'), ('confirm', 'Confirm'), ('done', 'Done'), |
|||
('cancel', 'Canceled')], string='Status', readonly=True, |
|||
default='draft', help="Defines the state of sales return") |
|||
source_pick_ids = fields.One2many('stock.picking', |
|||
'return_order_id', |
|||
string="Source Delivery", |
|||
domain="[('return_order_pick_id','=',False)]", |
|||
help="Shows the delivery orders of the " |
|||
"corresponding return order") |
|||
note = fields.Text(string="Note", help="The field can add the note") |
|||
to_refund = fields.Boolean(string='Update SO/PO Quantity', |
|||
help='Trigger a decrease of the delivered/' |
|||
'received quantity in' |
|||
' the associated Sale Order/Purchase Order') |
|||
|
|||
def return_confirm(self): |
|||
""" Confirm the sale return """ |
|||
if not self.source_pick_ids: |
|||
stock_picks = self.env['stock.picking'].search( |
|||
[('origin', '=', self.order_id.name)]) |
|||
moves = stock_picks.mapped('move_ids_without_package').filtered( |
|||
lambda p: p.product_id == self.product_id) |
|||
else: |
|||
moves = self.source_pick_ids.mapped( |
|||
'move_ids_without_package').filtered( |
|||
lambda p: p.product_id == self.product_id) |
|||
if moves: |
|||
moves = moves.sorted('product_uom_qty', reverse=True) |
|||
pick = moves[0].picking_id |
|||
vals = {'picking_id': pick.id} |
|||
return_pick_wizard = self.env['stock.return.picking'].create(vals) |
|||
return_pick_wizard._onchange_picking_id() |
|||
return_pick_wizard.product_return_moves.unlink() |
|||
lines = {'product_id': self.product_id.id, |
|||
"quantity": self.quantity, |
|||
'wizard_id': return_pick_wizard.id, |
|||
'move_id': moves[0].id, 'to_refund': self.to_refund} |
|||
self.env['stock.return.picking.line'].create(lines) |
|||
return_pick = return_pick_wizard._create_returns() |
|||
if return_pick: |
|||
return_pick = self.env['stock.picking'].browse(return_pick[0]) |
|||
return_pick.write( |
|||
{ |
|||
'note': self.reason, |
|||
'return_order_id': False, |
|||
'return_order_pick_id': self.id, |
|||
'return_order_picking': True}) |
|||
self.write({'state': 'confirm'}) |
|||
|
|||
def return_cancel(self): |
|||
""" Cancel the return """ |
|||
self.write({'state': 'cancel'}) |
|||
if self.stock_picking_ids: |
|||
for rec in self.stock_picking_ids.filtered( |
|||
lambda s: s.state not in ['done', 'cancel']): |
|||
rec.action_cancel() |
|||
|
|||
def _get_report_base_filename(self): |
|||
""" Passing the record name as report name |
|||
:return: |
|||
""" |
|||
self.ensure_one() |
|||
return 'Sale Return - %s' % (self.name) |
|||
|
|||
def _compute_access_url(self): |
|||
""" For computing the access url for each sale order """ |
|||
super(SaleReturn, self)._compute_access_url() |
|||
for order in self: |
|||
order.access_url = '/my/return_orders/%s' % order.id |
|||
|
|||
@api.depends('stock_picking_ids', 'state') |
|||
def _compute_delivery_picking_count(self): |
|||
""" Function to compute picking and delivery counts """ |
|||
for rec in self: |
|||
rec.delivery_count = 0 |
|||
rec.picking_count = 0 |
|||
if rec.source_pick_ids: |
|||
rec.delivery_count = len(rec.source_pick_ids) |
|||
else: |
|||
rec.delivery_count = self.env['stock.picking'].search_count( |
|||
[('return_order_id', 'in', self.ids), |
|||
('return_order_picking', '=', False)]) |
|||
if rec.stock_picking_ids: |
|||
rec.picking_count = len(rec.stock_picking_ids) |
|||
else: |
|||
rec.picking_count = self.env['stock.picking'].search_count( |
|||
[('return_order_pick_id', 'in', self.ids), |
|||
('return_order_picking', '=', True)]) |
|||
|
|||
def action_view_picking(self): |
|||
""" Function to view the stock picking transfers """ |
|||
action = self.env["ir.actions.actions"]._for_xml_id( |
|||
"stock.action_picking_tree_all") |
|||
pickings = self.mapped('stock_picking_ids') |
|||
if not self.stock_picking_ids: |
|||
pickings = self.env['stock.picking'].search( |
|||
[('return_order_pick_id', '=', self.id), |
|||
('return_order_picking', '=', True)]) |
|||
if len(pickings) > 1: |
|||
action['domain'] = [('id', 'in', pickings.ids)] |
|||
elif pickings: |
|||
form_view = [(self.env.ref('stock.view_picking_form').id, 'form')] |
|||
if 'views' in action: |
|||
action['views'] = form_view + [(state, view) for state, view in |
|||
action['views'] if |
|||
view != 'form'] |
|||
else: |
|||
action['views'] = form_view |
|||
action['res_id'] = pickings.id |
|||
# Prepare the context. |
|||
picking_id = pickings.filtered( |
|||
lambda l: l.picking_type_id.code == 'outgoing') |
|||
if picking_id: |
|||
picking_id = picking_id[0] |
|||
else: |
|||
picking_id = pickings[0] |
|||
action['context'] = dict( |
|||
self._context, |
|||
default_partner_id=self.partner_id.id, |
|||
default_picking_type_id=picking_id.picking_type_id.id) |
|||
return action |
|||
|
|||
def action_view_delivery(self): |
|||
""" Function to view the delivery transfers """ |
|||
action = self.env["ir.actions.actions"]._for_xml_id( |
|||
"stock.action_picking_tree_all") |
|||
pickings = self.mapped('stock_picking_ids') |
|||
if not self.stock_picking_ids: |
|||
pickings = self.env['stock.picking'].search( |
|||
[('return_order_id', '=', self.id), |
|||
('return_order_picking', '=', False)]) |
|||
if len(pickings) > 1: |
|||
action['domain'] = [('id', 'in', pickings.ids)] |
|||
elif pickings: |
|||
form_view = [(self.env.ref('stock.view_picking_form').id, 'form')] |
|||
if 'views' in action: |
|||
action['views'] = form_view + [(state, view) for state, view in |
|||
action['views'] if |
|||
view != 'form'] |
|||
else: |
|||
action['views'] = form_view |
|||
action['res_id'] = pickings.id |
|||
# Prepare the context. |
|||
picking_id = pickings.filtered( |
|||
lambda l: l.picking_type_id.code == 'outgoing') |
|||
if picking_id: |
|||
picking_id = picking_id[0] |
|||
else: |
|||
picking_id = pickings[0] |
|||
action['context'] = dict( |
|||
self._context, |
|||
default_partner_id=self.partner_id.id, |
|||
default_picking_type_id=picking_id.picking_type_id.id) |
|||
return action |
|||
|
|||
@api.onchange('order_id', 'source_pick_ids') |
|||
def _onchange_sale_order(self): |
|||
""" All the fields are updated according to the sale order """ |
|||
delivery = None |
|||
if self.order_id: |
|||
self.partner_id = self.order_id.partner_id |
|||
delivery = self.env['stock.picking'].search( |
|||
[('origin', '=', self.order_id.name)]) |
|||
if self.source_pick_ids: |
|||
delivery = self.source_pick_ids |
|||
if delivery: |
|||
product_ids = delivery.move_ids_without_package.mapped( |
|||
'product_id').ids |
|||
delivery = delivery.ids |
|||
else: |
|||
product_ids = self.order_id.order_line.mapped('product_id').ids |
|||
return {'domain': {'source_pick_ids': [('id', 'in', delivery)], |
|||
'product_id': [('id', 'in', product_ids)]}} |
|||
|
|||
@api.onchange('product_id') |
|||
def _onchange_product_id(self): |
|||
""" Update the received quantity based on the selected product and |
|||
source pickings. """ |
|||
if self.product_id and self.source_pick_ids: |
|||
moves = self.source_pick_ids.mapped( |
|||
'move_ids_without_package').filtered( |
|||
lambda p: p.product_id == self.product_id) |
|||
if moves: |
|||
self.received_qty = sum(moves.mapped('quantity_done')) |
@ -0,0 +1,53 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################### |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: Aysha Shalin (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################### |
|||
from odoo import fields, models |
|||
|
|||
|
|||
class StockPicking(models.Model): |
|||
""" Inheriting the model stock picking and adding custom fields """ |
|||
_inherit = 'stock.picking' |
|||
|
|||
return_order_id = fields.Many2one('sale.return', |
|||
string='Return order', |
|||
help="Shows the return order of current" |
|||
"transfer") |
|||
return_order_pick_id = fields.Many2one('sale.return', |
|||
string='Return order Pick', |
|||
help="Shows the return order picking" |
|||
"of current return order") |
|||
return_order_picking = fields.Boolean(string='Return order picking', |
|||
help="Helps to identify delivery and " |
|||
"return picking, if true the tra" |
|||
"nsfer is return picking else de" |
|||
"livery") |
|||
|
|||
def button_validate(self): |
|||
""" Supering the function validating the stock moves """ |
|||
res = super(StockPicking, self).button_validate() |
|||
for rec in self: |
|||
if rec.return_order_pick_id: |
|||
if any(line.state != 'done' for line in |
|||
rec.return_order_pick_id.stock_picking_ids): |
|||
return res |
|||
else: |
|||
rec.return_order_pick_id.write({'state': 'done'}) |
|||
return res |
@ -0,0 +1,40 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################### |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: Aysha Shalin (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################### |
|||
from odoo import models |
|||
|
|||
|
|||
class StockReturnPicking(models.TransientModel): |
|||
""" Inherit stock.return.picking to create return orders """ |
|||
_inherit = 'stock.return.picking' |
|||
|
|||
def _create_returns(self): |
|||
""" Creating return orders """ |
|||
new_picking, pick_type_id = super( |
|||
StockReturnPicking,self)._create_returns() |
|||
picking = self.env['stock.picking'].browse(new_picking) |
|||
if self.picking_id.return_order_id: |
|||
picking.write({'return_order_picking': False, |
|||
'return_order_id': False, |
|||
'return_order_pick_id': |
|||
self.picking_id.return_order_id.id}) |
|||
self.picking_id.return_order_id.write({'state': 'confirm'}) |
|||
return new_picking, pick_type_id |
@ -0,0 +1,92 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################### |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: Aysha Shalin (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################### |
|||
from odoo import fields, models |
|||
|
|||
|
|||
class Website(models.Model): |
|||
""" Inheriting Website to add contact fields """ |
|||
_inherit = 'website' |
|||
|
|||
mobile_number = fields.Char(string='Mobile Number', |
|||
help="Defines the mobile number") |
|||
company = fields.Boolean(string="Company Name", |
|||
help='If it is true it will show company name on ' |
|||
'website') |
|||
address = fields.Boolean(string="Address", |
|||
help='If it is true it will show address on ' |
|||
'website') |
|||
phone = fields.Boolean(string="Phone", |
|||
help='If it is true it will show phone number on ' |
|||
'website') |
|||
mobile = fields.Boolean(string="Mobile", |
|||
help='If it is true it will show mobile ' |
|||
'number on website') |
|||
email = fields.Boolean(string="Email", |
|||
help='If it is true it will show email ' |
|||
'on website') |
|||
website = fields.Boolean(string="Website", |
|||
help='If it is true it will show ' |
|||
'website name on website') |
|||
vat = fields.Boolean(string="VAT", help='If it is true it will show tax id ' |
|||
'on website') |
|||
address_in_online = fields.Boolean(string="Address in one line", |
|||
help='If it is true it will show address' |
|||
' in one line on website') |
|||
hide_marker_icons = fields.Boolean(string="Hide Marker Icons", |
|||
help='If it is true it will hide all ico' |
|||
'ns of address on website') |
|||
show_phone_icon = fields.Boolean(string="Show Phone Icons", |
|||
help='If it is true it will show only phon' |
|||
'e icons on website') |
|||
country_flag = fields.Boolean(string="Country Flag", |
|||
help='If it is true it will ' |
|||
'show country flag on website') |
|||
facebook = fields.Boolean(string="Facebook", |
|||
help='If it is true it will show ' |
|||
'company name on website') |
|||
social_facebook = fields.Char(string="Facebook Account", |
|||
related='company_id.social_facebook', |
|||
readonly=False, |
|||
help="Company Facebook Account") |
|||
twitter = fields.Boolean(string="Twitter", help='If it is true it will' |
|||
'show twitter on website') |
|||
social_twitter = fields.Char(string="Twitter Account", |
|||
related='company_id.social_twitter', |
|||
readonly=False, help='Twitter account') |
|||
linked_in = fields.Boolean(string="LinkedIn", |
|||
help='If it is true it will show twitter ' |
|||
'on website') |
|||
social_linked_in = fields.Char(string="Linkedin Account", |
|||
related='company_id.social_linkedin', |
|||
readonly=False, help='Linkedin account') |
|||
instagram = fields.Boolean(string="Instagram", |
|||
help='If it is true it will show twitter on ' |
|||
'website') |
|||
social_instagram = fields.Char(string="Instagram Account", |
|||
related='company_id.social_instagram', |
|||
readonly=False, help='Instagram account') |
|||
git_hub = fields.Boolean(string="GitHub", |
|||
help='If it is true it will show twitter on' |
|||
' website') |
|||
social_git_hub = fields.Char(string="Github Account", |
|||
related='company_id.social_github', |
|||
readonly=False, help='Github Account') |
@ -0,0 +1,14 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<odoo> |
|||
<!-- Sales Return Report Record --> |
|||
<record id="report_sale_return" model="ir.actions.report"> |
|||
<field name="name">Sale Return</field> |
|||
<field name="model">sale.return</field> |
|||
<field name="report_type">qweb-pdf</field> |
|||
<field name="report_name">all_in_one_website_kit.report_salereturn</field> |
|||
<field name="report_file">all_in_one_website_kit.report_salereturn</field> |
|||
<field name="print_report_name">'Sale Retun - %s' % object.name</field> |
|||
<field name="binding_model_id" ref="model_sale_return"/> |
|||
<field name="binding_type">report</field> |
|||
</record> |
|||
</odoo> |
@ -0,0 +1,75 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<odoo> |
|||
<!-- Sales Return Report Template --> |
|||
<template id="report_salereturn"> |
|||
<t t-call="web.html_container"> |
|||
<t t-foreach="docs" t-as="doc"> |
|||
<t t-call="all_in_one_website_kit.report_sale_return_template" |
|||
t-lang="doc.partner_id.lang"/> |
|||
</t> |
|||
</t> |
|||
</template> |
|||
<template id="report_sale_return_template"> |
|||
<t t-call="web.external_layout"> |
|||
<t t-set="doc" |
|||
t-value="doc.with_context(lang=doc.partner_id.lang)"/> |
|||
<div class="page"> |
|||
<div class="oe_structure"/> |
|||
<h2 class="mt16"> |
|||
<span>Return Order #</span> |
|||
<span t-field="doc.name"/> |
|||
</h2> |
|||
<div class="row mt32 mb32" id="informations"> |
|||
<div t-if="doc.partner_id" |
|||
class="col-auto col-3 mw-100 mb-2"> |
|||
<strong>Customer:</strong> |
|||
<p class="m-0" t-field="doc.partner_id"/> |
|||
</div> |
|||
<div t-if="doc.order_id" class="col-auto col-3 mw-100 mb-2"> |
|||
<strong>Sale Order:</strong> |
|||
<p class="m-0" t-field="doc.order_id"/> |
|||
</div> |
|||
<div t-if="doc.create_date" |
|||
class="col-auto col-3 mw-100 mb-2"> |
|||
<strong>Creation Date:</strong> |
|||
<p class="m-0" t-field="doc.create_date" |
|||
t-options='{"widget": "date"}'/> |
|||
</div> |
|||
<div t-if="doc.user_id" |
|||
class="col-auto col-3 mw-100 mb-2" |
|||
name="expiration_date"> |
|||
<strong>Responsible:</strong> |
|||
<p class="m-0" t-field="doc.user_id"/> |
|||
</div> |
|||
</div> |
|||
<table class="table table-sm o_main_table"> |
|||
<!-- In case we want to repeat the header, remove "display: table-row-group" --> |
|||
<thead style="display: table-row-group"> |
|||
<tr> |
|||
<th name="th_description" class="text-left"> |
|||
Product |
|||
</th> |
|||
<th name="th_quantity" class="text-right">Quantity |
|||
</th> |
|||
</tr> |
|||
</thead> |
|||
<tbody class="sale_tbody"> |
|||
<tr t-att-class="'bg-200 font-weight-bold'"> |
|||
<td name="td_product"> |
|||
<span t-field="doc.product_id"/> |
|||
</td> |
|||
<td name="td_quantity" class="text-right"> |
|||
<span t-field="doc.quantity"/> |
|||
<span t-field="doc.product_id.uom_id"/> |
|||
</td> |
|||
</tr> |
|||
</tbody> |
|||
</table> |
|||
<div t-if="doc.partner_id" class="col-auto col-3 mw-100 mb-2"> |
|||
<strong>Reason:</strong> |
|||
<p class="m-0" t-field="doc.reason"/> |
|||
</div> |
|||
</div> |
|||
</t> |
|||
</template> |
|||
</odoo> |
|
After Width: | Height: | Size: 3.6 KiB |
After Width: | Height: | Size: 310 B |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 576 B |
After Width: | Height: | Size: 733 B |
After Width: | Height: | Size: 911 B |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 673 B |
After Width: | Height: | Size: 878 B |
After Width: | Height: | Size: 653 B |
After Width: | Height: | Size: 905 B |
After Width: | Height: | Size: 839 B |
After Width: | Height: | Size: 427 B |
After Width: | Height: | Size: 627 B |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 988 B |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 4.4 KiB |
After Width: | Height: | Size: 589 B |
After Width: | Height: | Size: 3.4 KiB |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 967 B |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 3.8 KiB |
After Width: | Height: | Size: 5.0 KiB |
After Width: | Height: | Size: 50 KiB |
After Width: | Height: | Size: 47 KiB |
After Width: | Height: | Size: 48 KiB |
After Width: | Height: | Size: 49 KiB |
After Width: | Height: | Size: 50 KiB |
After Width: | Height: | Size: 48 KiB |
After Width: | Height: | Size: 141 KiB |
After Width: | Height: | Size: 218 KiB |
After Width: | Height: | Size: 130 KiB |
After Width: | Height: | Size: 25 KiB |
After Width: | Height: | Size: 302 KiB |
After Width: | Height: | Size: 501 KiB |
After Width: | Height: | Size: 209 KiB |
After Width: | Height: | Size: 112 KiB |
After Width: | Height: | Size: 214 KiB |
After Width: | Height: | Size: 156 KiB |
After Width: | Height: | Size: 214 KiB |
After Width: | Height: | Size: 39 KiB |
After Width: | Height: | Size: 147 KiB |
After Width: | Height: | Size: 94 KiB |
After Width: | Height: | Size: 220 KiB |
After Width: | Height: | Size: 97 KiB |
After Width: | Height: | Size: 336 KiB |
After Width: | Height: | Size: 482 KiB |
After Width: | Height: | Size: 102 KiB |
After Width: | Height: | Size: 180 KiB |
After Width: | Height: | Size: 102 KiB |
After Width: | Height: | Size: 60 KiB |
After Width: | Height: | Size: 102 KiB |
After Width: | Height: | Size: 103 KiB |
After Width: | Height: | Size: 48 KiB |
After Width: | Height: | Size: 190 KiB |
After Width: | Height: | Size: 138 KiB |
After Width: | Height: | Size: 506 KiB |
After Width: | Height: | Size: 131 KiB |
After Width: | Height: | Size: 96 KiB |
After Width: | Height: | Size: 163 KiB |
After Width: | Height: | Size: 137 KiB |
After Width: | Height: | Size: 68 KiB |
After Width: | Height: | Size: 94 KiB |