@ -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 |