Commit 857ba3b1 by Administrator

Merge branch 'aide_a_la_commande' into 'dev_cooperatic'

Aide a la commande

See merge request !35
parents ae3dbb0f e7f80fe7
Pipeline #1101 failed with stage
in 36 seconds
......@@ -52,7 +52,7 @@ class CagetteInventory(models.Model):
file_data = json.load(json_file)
date_time = datetime.fromtimestamp(int(filename))
d = date_time.strftime("%m/%d/%Y, %H:%M")
d = date_time.strftime("%d/%m/%Y, %H:%M")
file_data['id'] = int(filename)
file_data['datetime_created'] = d
......@@ -113,7 +113,7 @@ class CagetteInventory(models.Model):
return file_data['inventory_status']
@staticmethod
def create_custom_inv_file(line_ids, line_type):
def create_custom_inv_file(line_ids, line_type, default_partners_id=[]):
res = {}
try:
......@@ -127,36 +127,54 @@ class CagetteInventory(models.Model):
api = OdooAPI()
ids = []
order = ['', '']
user = partner = ''
fields = ['create_uid', 'product_id', 'partner_id']
cond = [['id', 'in', line_ids]]
if (line_type == 'cpo'):
model = 'computed.purchase.order.line'
fields += ['computed_purchase_order_id']
user = ''
partners = []
if len(default_partners_id) > 0:
f = ['name']
c = [['id', 'in', default_partners_id]]
partners_name = api.search_read('res.partner', c, f)
for p in partners_name:
partners.append(p['name'])
if line_type == 'product_templates':
fields = ['id']
cond = [['product_tmpl_id', 'in', line_ids]]
model = 'product.product'
user="api"
else:
model = 'purchase.order.line'
fields += ['order_id']
fields = ['create_uid', 'product_id', 'partner_id']
cond = [['id', 'in', line_ids]]
if (line_type == 'cpo'):
model = 'computed.purchase.order.line'
fields += ['computed_purchase_order_id']
else:
model = 'purchase.order.line'
fields += ['order_id']
lines = api.search_read(model, cond, fields)
if len(lines) == len(line_ids):
for l in lines:
ids.append(l['product_id'][0])
user = l['create_uid'][1]
if (line_type == 'cpo'):
order = l['computed_purchase_order_id']
if line_type == 'product_templates':
ids.append(l['id'])
else:
order = l['order_id']
partner = l['partner_id'][1]
ids.append(l['product_id'][0])
user = l['create_uid'][1]
if (line_type == 'cpo'):
order = l['computed_purchase_order_id']
else:
order = l['order_id']
partners.append(l['partner_id'][1])
if (line_type == 'cpo'):
# partner_id isn't defined
f = ['partner_id']
c = [['id', '=', int(order[0])]]
cpo = api.search_read('computed.purchase.order', c, f)
if len(cpo) > 0:
partner = cpo[0]['partner_id'][1]
partners.append(cpo[0]['partner_id'][1])
file_data = {
'order': order[1],
'user': user,
'partner': partner,
'partners': partners,
'inventory_status': '',
'products': ids
}
......
......@@ -4,6 +4,13 @@ var shelfs_table = null,
function init_datatable() {
// For a smooth migration...
for (const i in lists) {
if (('partners' in lists[i]) === false) {
lists[i]['partners'] = [lists[i]['partner']]
}
}
return $('#lists').DataTable({
data: lists, // data passed at page loading
rowId: 'id',
......@@ -17,8 +24,15 @@ function init_datatable() {
}
},
{
data:"partner",
title:"Fournisseur"
data:"partners",
title:"Fournisseur(s)",
render: function (data) {
res = "";
for (const i in data) {
res += `${data[i]}<br/>`;
}
return res;
}
},
{
data:"order",
......
......@@ -43,7 +43,6 @@ def custom_list_inventory(request, id):
products = CagetteInventory.get_custom_list_products(id)
if 'error' in products:
print(products)
products['data'] = []
context = {'title': 'Inventaire',
......@@ -112,10 +111,25 @@ def do_custom_list_inventory(request):
def generate_inventory_list(request):
"""Responding to Odoo ajax call (no csrf)."""
res = {}
default_partners_id = []
try:
lines = json.loads(request.POST.get('lines'))
ltype = request.POST.get('type')
res = CagetteInventory.create_custom_inv_file(lines, ltype)
except Exception as e:
try:
# POST.get() returns None when request from django
data = json.loads(request.body.decode())
lines = data["lines"]
ltype = data["type"]
if "partners_id" in data:
default_partners_id = data["partners_id"]
except Exception as ee:
res['error'] = str(ee)
coop_looger.error("generate_inventory_list : %s", str(e))
return JsonResponse(res, status=500)
try:
res = CagetteInventory.create_custom_inv_file(lines, ltype, default_partners_id)
except Exception as e:
res['error'] = str(e)
coop_looger.error("generate_inventory_list : %s", str(e))
......
......@@ -268,3 +268,15 @@ class Orders(models.Model):
coop_logger.error('Orders get_custom_barcode_labels_to_print(oids) : %s', str(e))
return labels_data
class CagetteSuppliers(models.Model):
@staticmethod
def get_suppliers():
api = OdooAPI()
f = ['id', 'name', 'display_name']
c = [['supplier', '=', 1], ['parent_id', '=', False]]
res = api.search_read('res.partner', c, f)
return res
.page_body{
position: relative;
}
.page_content {
position: absolute;
top: 0;
left: 0;
right: 0;
}
/* - Common */
.pill {
border-radius: 30px;
min-width: 200px;
min-height: 35px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
padding: 8px 15px 8px 15px;
margin: 0 10px 5px 0;
}
.disabled {
background-color: #c9cbce;
}
.disabled:hover {
background-color: #a1a2a3;
}
/* - Order selection screen */
#new_order_area {
margin-bottom: 40px;
}
#new_order_form {
margin-top: 20px;
}
#existing_orders {
display: flex;
justify-content: center;
align-items: center;
flex-wrap: wrap;
width: 80%;
margin: 0 auto;
padding-top: 15px;
}
.order_last_update {
font-weight: bold;
}
.order_modified_msg {
font-size: 2rem;
color: #e62720;
}
/* - Main screen */
/* -- Top action button(s) */
#back_to_order_selection {
position: absolute;
}
#actions_buttons_area {
position: absolute;
top: 0;
right: 0;
}
/* -- Supplier form */
#supplier_form_container {
margin-top: 30px;
}
#supplier_input {
width: 500px;
margin-right: 10px;
border-radius: 5px;
}
/* -- Table */
#products_table_filter{
text-align: right !important;
}
#products_table_filter input{
height: 40px;
}
#table_header_select_all{
display: flex;
align-content: center;
justify-content: center;
flex-wrap: wrap;
}
#table_header_select_all input{
margin-left: 5px;
}
.product_qty_input {
width: 100px;
}
.product_not_from_supplier {
background-color: #e7e9ed;
cursor: pointer;
}
.product_name, .supplier_name {
font-weight: bold;
}
.select_product_cb {
cursor: pointer;
}
/* -- Suppliers list */
#suppliers_container {
display: flex;
justify-content: center;
align-items: center;
flex-wrap: wrap;
margin: 20px 0 20px 0;
}
.supplier_pill {
background-color: #e7e9ed;
}
.remove_supplier_icon {
color: red;
margin-left: 5px;
cursor: pointer;
}
\ No newline at end of file
......@@ -8,5 +8,9 @@ urlpatterns = [
url(r'^export/([0-9]+)', views.export_one),
url(r'^export/([a-z]+)', views.export_regex),
url(r'^get_pdf_labels$', views.get_pdf_labels),
url(r'^print_product_labels$', views.print_product_labels)
url(r'^print_product_labels$', views.print_product_labels),
url(r'^helper$', views.helper),
url(r'^get_suppliers$', views.get_suppliers),
url(r'^get_supplier_products$', views.get_supplier_products),
url(r'^associate_supplier_to_product$', views.associate_supplier_to_product),
]
from outils.common_imports import *
from outils.for_view_imports import *
from orders.models import Order, Orders
from products.models import CagetteProduct
from orders.models import Order, Orders, CagetteSuppliers
from products.models import CagetteProduct, CagetteProducts
from openpyxl import Workbook
from openpyxl.writer.excel import save_virtual_workbook
......@@ -13,6 +13,52 @@ def as_text(value): return str(value) if value is not None else ""
def index(request):
return HttpResponse('Orders')
def helper(request):
context = {
'title': 'Aide à la commande',
'couchdb_server': settings.COUCHDB['url'],
'db': settings.COUCHDB['dbs']['orders']
}
template = loader.get_template('orders/helper.html')
return HttpResponse(template.render(context, request))
def get_suppliers(request):
""" Get suppliers list """
res = {}
try:
res = CagetteSuppliers.get_suppliers()
except Exception as e:
res["error"] = str(e)
return JsonResponse(res, status=500)
return JsonResponse({'res': res})
def get_supplier_products(request):
""" Get supplier products """
sid = request.GET.get('sid', '')
res = CagetteProducts.get_products_by_supplier(sid)
if 'error' in res:
return JsonResponse(res, status=500)
else:
return JsonResponse({'res': res})
def associate_supplier_to_product(request):
""" This product is now supplied by this supplier """
res = {}
try:
data = json.loads(request.body.decode())
res = CagetteProduct.associate_supplier_to_product(data["product_tmpl_id"], data["supplier_id"])
except Exception as e:
res["error"] = str(e)
return JsonResponse(res, status=500)
return JsonResponse({'res': res})
def export_one(request, oid):
msg = ''
try:
......
......@@ -99,6 +99,7 @@ STATICFILES_DIRS = (
"website/static",
"shop/static",
"shelfs/static",
"orders/static",
# "tests/static"
)
......
......@@ -19,7 +19,8 @@ COUCHDB = {
'member': 'coops',
'inventory': 'inventory',
'envelops': 'envelop',
'shop': 'shopping_carts'
'shop': 'shopping_carts',
'orders': 'orders_test'
}
}
......
......@@ -6,6 +6,7 @@ from outils.common import OdooAPI
import csv
import tempfile
import pymysql.cursors
import datetime
vcats = []
......@@ -126,6 +127,27 @@ class CagetteProduct(models.Model):
res = api.create('product.supplier.shortage', f)
return res
@staticmethod
def associate_supplier_to_product(product_tmpl_id, partner_id):
api = OdooAPI()
f = ["id", "standard_price", "purchase_ok"]
c = [['product_tmpl_id', '=', product_tmpl_id]]
res_products = api.search_read('product.product', c, f)
product = res_products[0]
f = {
'product_tmpl_id' : product_tmpl_id,
'product_id' : product["id"],
'name' : partner_id,
'product_purchase_ok': product["purchase_ok"],
'price': product["standard_price"], # By default, use product price
'base_price': product["standard_price"],
}
res = api.create('product.supplierinfo', f)
return res
class CagetteProducts(models.Model):
"""Initially used to make massive barcode update."""
......@@ -387,6 +409,43 @@ class CagetteProducts(models.Model):
bc_map[bc] = bc
return bc_map
@staticmethod
def get_products_by_supplier(supplier_id):
api = OdooAPI()
res = {}
# todo : try with no result
try:
today = datetime.date.today().strftime("%Y-%m-%d")
# Get products/supplier relation
f = ["product_tmpl_id", 'date_start', 'date_end']
c = [['name', '=', int(supplier_id)]]
psi = api.search_read('product.supplierinfo', c, f)
# Filter valid data
ptids = []
for p in psi:
if (p["product_tmpl_id"] is not False
and (p["date_start"] is False or p["date_end"] is not False and p["date_start"] <= today)
and (p["date_end"] is False or p["date_end"] is not False and p["date_end"] >= today)):
ptids.append(p["product_tmpl_id"][0])
# Get products templates
f = ["id", "state", "name", "default_code", "qty_available", "incoming_qty", "uom_id"]
c = [['id', 'in', ptids], ['purchase_ok', '=', True]]
products_t = api.search_read('product.template', c, f)
filtered_products_t = [p for p in products_t if p["state"] != "end" and p["state"] != "obsolete"]
# Note: if product.product is needed, get "product_variant_ids" from product template
res["products"] = filtered_products_t
except Exception as e:
print(str(e))
res["error"] = str(e)
return res
class OFF(models.Model):
"""OpenFoodFact restricted DB queries."""
......
......@@ -10,10 +10,6 @@ def index(request):
context = {'title': 'Export de ventes'}
template = loader.get_template('sales/index.html')
# m = CagetteSales()
# sales = m.get_sales()
# print(sales)
return HttpResponse(template.render(context, request))
def get_sales(request):
......
......@@ -34,7 +34,7 @@
</div>
<script type="text/javascript">
lists = {{lists|safe}}
var lists = {{lists|safe}}
</script>
<script src="{% static "js/all_common.js" %}?v="></script>
<script src="{% static "js/common.js" %}?v="></script>
......
{% extends "base.html" %}
{% load static %}
{% block additionnal_css %}
<link rel="stylesheet" href="{% static 'css/datatables/jquery.dataTables.css' %}">
<link rel="stylesheet" href="{% static 'jquery-ui-1.12.1/jquery-ui.min.css' %}">
<link rel="stylesheet" href="{% static 'css/oders_helper_style.css' %}">
{% endblock %}
{% block additionnal_scripts %}
<script type="text/javascript" src="{% static 'jquery-ui-1.12.1/jquery-ui.min.js' %}?v="></script>
<script type="text/javascript" src="{% static 'js/datatables/jquery.dataTables.min.js' %}"></script>
<script type="text/javascript" src="{% static 'js/notify.min.js' %}?v="></script>
{% endblock %}
{% block content %}
<div class="page_body">
<div id="select_order_content" class="page_content txtcenter">
<div id="new_order_area">
<h2>Créer une nouvelle commande</h2>
<form id="new_order_form">
<input type="text" id="new_order_name" placeholder="Nom de la commande...">
<button type="submit" class="btn btn--primary">Valider</button>
</form>
</div>
<div id="existing_orders_area">
<h2>Ou, continuer une commande existante</h2>
<div id="existing_orders"></div>
</div>
</div>
<div id="main_content" class="page_content" style="display:none;">
<div id="back_to_order_selection">
<button type="button" class="btn--danger"><i class="fas fa-arrow-left"></i>&nbsp; Retour</button>
</div>
<div id="actions_buttons_area">
<button type="button" class='btn--primary' id="do_inventory">Faire un inventaire</button>
</div>
<div class="header txtcenter">
<h1>Aide à la commande</h1>
<i>Commande : <span class="order_name_container"></span></i>
</div>
<div class="txtcenter" id="supplier_form_container">
<form action="javascript:;" id="supplier_form">
<input type="text" name="supplier" id="supplier_input" placeholder="Rechercher un fournisseur par son nom">
<button type="submit" class='btn--primary'>Ajouter le fournisseur</button>
</form>
</div>
<div class="txtcenter" id="suppliers_container"></div>
<div class="main" style="display:none;">
<div class="table_area">
<table id="products_table" class="display" cellspacing="0" width="100%"></table>
</div>
</div>
</div>
<div id="templates" style="display:none;">
<div id="supplier_pill_template">
<div class="pill supplier_pill">
<div class="supplier_name_container">
<span class="pill_supplier_name"></span>
<i class="fas fa-times remove_supplier_icon"></i>
</div>
</div>
</div>
<div id="order_pill_template">
<div class="pill order_pill btn btn--primary">
<span class="pill_order_name"></span>
</div>
</div>
<div id="modal_order_access">
<h3>Attention !</h3>
<br/>
<p class="order_modified_msg">
Un autre navigateur a modifié cette commande il y a <span class="order_last_update"></span>.
</p><br/>
<p>
Si quelqu'un d'autre que vous est à l'origine de la modification et que celle-ci est récente,
nous conseillons fortement de ne pas accéder à la commande afin d'éviter les conflits.
</p><br/>
<p>Voulez-vous quand même y accéder ?</p>
<hr/>
</div>
<div id="modal_remove_supplier">
<h3>Attention !</h3>
<p>
Vous vous apprêtez à supprimer le fournisseur <span class="supplier_name"></span> de la sélection.<br/>
Les produits associés uniquement à ce fournisseur seront supprimés du tableau.<br/>
Les données renseignées dans la colonne de ce fournisseur seront perdues.
</p>
<p>Êtez-vous sûr ?</p>
<hr/>
</div>
<div id="modal_attach_product_to_supplier">
<h3>Attention !</h3>
<p>
Vous vous apprêtez à associer le produit <span class="product_name"></span> au fournisseur <span class="supplier_name"></span>.<br/>
L'association sera sauvegardée dès que vous aurez cliqué sur "Valider".<br/>
</p>
<p>Êtez-vous sûr ?</p>
<hr/>
</div>
<div id="modal_create_inventory">
<p>
Vous vous apprêtez à créer un inventaire de <span class="inventory_products_count"></span> produits.
</p>
<p>Êtez-vous sûr ?</p>
<hr/>
</div>
</div>
</div>
<script src="{% static "js/pouchdb.min.js" %}"></script>
<script type="text/javascript">
var couchdb_dbname = '{{db}}';
var couchdb_server = '{{couchdb_server}}' + couchdb_dbname;
</script>
<script src="{% static "js/all_common.js" %}?v="></script>
<script type="text/javascript" src="{% static 'js/orders_helper.js' %}?v="></script>
{% endblock %}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment