Commit 8452c697 by François C.

Merge branch 'dev_principale' into 'dev_cooperatic'

# Conflicts:
#   coops_configurations/config_lacagette.py
parents e7104477 dfda5d22
Pipeline #1023 passed with stage
in 21 seconds
# Scripts
*.sh text eol=lf
\ No newline at end of file
......@@ -16,3 +16,4 @@ db.sqlite3
.gitlab-ci.yml
shop/shop_admin_settings.json
shop/errors.log
.idea
This diff is collapsed. Click to expand it.
......@@ -102,4 +102,8 @@ ENTRANCE_COME_FOR_SHOPING_MSG = "Hey coucou toi ! Cet été nous sommes plus de
UNSUBSCRIBED_MSG = 'Vous êtes désincrit·e, merci de remplir <a href="https://docs.google.com/forms/d/e/1FAIpQLSfPiC2PkSem9x_B5M7LKpoFNLDIz0k0V5I2W3Mra9AnqnQunw/viewform">ce formulaire</a> pour vous réinscrire sur un créneau.<br />Vous pouvez également contacter le Bureau des Membres en remplissant <a href="https://docs.google.com/forms/d/e/1FAIpQLSeZP0m5-EXPVJxEKJk6EjwSyZJtnbiGdYDuAeFI3ENsHAOikg/viewform">ce formulaire</a>'
CONFIRME_PRESENT_BTN = 'Clique ici pour valider ta présence'
RECEPTION_PB = "Ici, vous pouvez signaler toute anomalie lors d'une réception, les produits non commandés, cassés ou pourris. \
Merci d'indiquer un maximum d'informations, le nom du produit et son code barre. \
Dans le cas de produits déteriorés, merci d'envoyer une photo avec votre téléphone à [Adresse_email]"
{
"views": {
"by_fp": {
"map": "function(doc){emit(doc.fingerprint);}"
},
"by_completed": {
"map": "function(doc){emit(doc.completed);}"
},
"by_odoo_id": {
"map": "function(doc){emit(doc.odoo_id);}"
}
}
}
{
"views": {
"by_type": {
"map": "function(doc){emit(doc.type);}"
}
}
}
#!/usr/bin/env sh
sleep 3
curl -X PUT http://admin:123abc@couchdb:5984/coops
curl -X PUT http://admin:123abc@couchdb:5984/inventory
curl -X PUT http://admin:123abc@couchdb:5984/envelop
curl -X PUT http://admin:123abc@couchdb:5984/shopping_carts
curl -X PUT http://admin:123abc@couchdb:5984/coops/_design/index \
-d @couchdb-coops-init.json
curl -X PUT http://admin:123abc@couchdb:5984/envelop/_design/index \
-d @couchdb-envelop-init.json
do_shelf_inventory received data are beeing stored in this directory, to help for data recovery and analysis
\ No newline at end of file
Emplacements pour stocker les fichiers utiliser par des tâches programmées (par ex)
Les fichiers seront traités lors de l'appel à /reception/po_process_picking
......@@ -27,17 +27,6 @@ services:
volumes:
- "couchdb-data:/opt/couchdb/data"
initializer:
image: curlimages/curl
deploy:
restart_policy:
condition: on-failure
depends_on:
- couchdb
command: ["sh", "-c", "cd /tmp && ./couchdb-setup.sh"]
volumes:
- "./:/tmp"
database:
image: "postgres:10"
env_file: .env
......
FROM python:3-slim
FROM python:3
# Virtual env:
ENV VIRTUAL_ENV=/opt/venv
RUN python3 -m venv $VIRTUAL_ENV
ENV PATH="$VIRTUAL_ENV/bin:$PATH"
ENV PYTHONUNBUFFERED=1
# Add french locale
RUN apt update && \
apt install -y --no-install-recommends locales && \
rm -rf /var/lib/apt/lists/* && \
sed -i '/^#.* fr_FR.UTF-8 /s/^#//' /etc/locale.gen && \
locale-gen
WORKDIR /home/app
# Install dependencies:
RUN pip install --upgrade pip
COPY requirements.txt /home/app/
RUN pip install -r requirements.txt
# Setup volume to be able to dev application locally
VOLUME /home/app
COPY . /home/app
# Run the application:
EXPOSE 8080
......
[couchdb]
single_node=true
users_db_security_editable = true
[httpd]
enable_cors = true
[cors]
credentials = true
origins = http://127.0.0.1:8080
origins = *
[replicator]
db = _replicator
......
#! /bin/sh
#!/usr/bin/env bash
port=34001
ip=127.0.0.1
if [ ! -z "$1" ]
then
if [ -n "$1" ]
then
ip=$1
fi
if [ ! -z "$2" ]
then
if [ -n "$2" ]
then
port=$2
fi
current_path=$(pwd)
export PYTHONPATH="$current_path:$current_path/lib:$PYTHONPATH"
echo yes | django-admin collectstatic --settings=outils.settings
django-admin runserver $ip:$port --settings=outils.settings
export DJANGO_SETTINGS_MODULE=outils.settings
# Collect static files
echo yes | django-admin collectstatic
# Make sure couchdb databases exist
python manage.py couchdb
# Run server
django-admin runserver "$ip:$port"
Destination directory for logging files (defines in 'handlers' part of LOGGING definition)
https://docs.djangoproject.com/fr/2.2/topics/logging/
from django.core.management.base import BaseCommand, CommandError
from django.conf import settings
import couchdb
class Command(BaseCommand):
help = 'Initialize needed couchDB databases'
def handle(self, *args, **options):
if 'admin' not in settings.COUCHDB:
raise CommandError('''
Veuillez définir les accès d'admin à CouchDB dans votre fichier settings_secret.py
Vérifiez le fichier settings_secret_example.py pour un exemple.''')
url = settings.COUCHDB['admin']['url'] % (settings.COUCHDB['admin']['user'], settings.COUCHDB['admin']['password'])
dbnames = settings.COUCHDB['dbs']
couchserver = couchdb.Server(url)
for dbname in dbnames.values():
if dbname not in couchserver:
self.stdout.write(self.style.WARNING("Missing database %s" % dbname))
db = couchserver.create(dbname)
self.stdout.write(self.style.SUCCESS("✓ created db"))
if dbname == 'coops':
self.createCoopsViews(db)
elif dbname == 'envelop':
self.createEnvelopViews(db)
# db.security
self.createPublicAccess(db)
def createCoopsViews(self, dbConn):
byFpMapFunction = '''function(doc) {
emit(doc.fingerprint);
}'''
byCompletedMapFunction = '''function(doc) {
emit(doc.completed);
}'''
byOdooMapFunction = '''function(doc) {
emit(doc.odoo_id);
}'''
views = {
"by_fp": {
"map": byFpMapFunction
},
"by_completed": {
"map": byCompletedMapFunction
},
"by_odoo_id": {
"map": byOdooMapFunction
},
}
self.createView(dbConn, "index", views)
def createEnvelopViews(self, dbConn):
byTypeMapFunction = '''function(doc) {
emit(doc.type);
}'''
views = {
"by_type": {
"map": byTypeMapFunction
}
}
self.createView(dbConn, "index", views)
def createView(self, dbConn, designDoc, views):
self.stdout.write(self.style.SUCCESS("✓ created view %s" % designDoc))
data = {
"_id": "_design/%s" % designDoc,
"views": views,
"language": "javascript",
"options": {"partitioned": False }
}
dbConn.save(data)
def createPublicAccess(self, dbConn):
self.stdout.write(self.style.SUCCESS("✓ created security rule"))
security_doc = dbConn.resource.get_json("_security")[2]
dbConn.resource.put("_security", {})
......@@ -77,6 +77,9 @@ class OdooAPI:
class CouchDB:
"""Class to handle interactions with CouchDB"""
if 'private_url' in settings.COUCHDB:
url = settings.COUCHDB['private_url']
else:
url = settings.COUCHDB['url']
dbs = settings.COUCHDB['dbs']
db = None
......
......@@ -8,7 +8,13 @@ ODOO = {
}
COUCHDB = {
'private_url': 'http://couchdb:5984',
'url': 'http://127.0.0.1:5984',
'admin': {
'url': 'http://%s:%s@couchdb:5984',
'user': 'admin',
'password': '123abc',
},
'dbs': {
'member': 'coops',
'inventory': 'inventory',
......
......@@ -1347,7 +1347,7 @@ function openErrorReport() {
var textarea = document.getElementById("error_report");
textarea.value = user_comments;
textarea.value = (user_comments != undefined) ? user_comments : "";
textarea.focus();
textarea.setSelectionRange(textarea.value.length, textarea.value.length);
}
......
......@@ -2,6 +2,8 @@
from outils.common_imports import *
from outils.for_view_imports import *
from django.views.generic import View
from django.http import HttpResponse
from django.http import JsonResponse
import os
from datetime import date
......@@ -14,6 +16,9 @@ from outils.common import OdooAPI
from members.models import CagetteUser
from products.models import CagetteProduct
# create temp directory if needed
if not os.path.exists("temp"):
os.mkdir("temp")
def as_text(value):
""" Utils """
......@@ -74,10 +79,10 @@ def produits(request, id):
"TOOLS_SERVER": settings.TOOLS_SERVER}
fixed_barcode_prefix = '0490'
if hasattr(settings, 'RECEPTION_PB_EMAIL'):
context['RECEPTION_PB_EMAIL'] = settings.RECEPTION_PB_EMAIL
if hasattr(settings, 'RECEPTION_PB'):
context['RECEPTION_PB'] = settings.RECEPTION_PB
else:
context['RECEPTION_PB_EMAIL'] = ' [mail à renseigner dans config.py]'
context['RECEPTION_PB'] = ' [texte à renseigner dans config.py]'
if hasattr(settings, 'FIXED_BARCODE_PREFIX'):
fixed_barcode_prefix = settings.FIXED_BARCODE_PREFIX
......@@ -165,6 +170,9 @@ def update_orders(request):
import requests
# don't print barcode which begin with these codes
noprint_list = ["0493", "0492", "0499"]
rep = HttpResponse("Not")
if request.is_ajax():
if request.method == 'PUT':
......@@ -212,8 +220,8 @@ def update_orders(request):
except Exception as e:
errors.append('error registering shortage on p'+order_line['id']+':'+str(e))
# Print etiquette with new price if update if successful
if (print_labels is True) and (update is True) and (data['update_type'] == 'br_valid') and order_line['new_shelf_price']:
# Print etiquette with new price if update if successful and barcode is authorized
if (print_labels is True) and (update is True) and (data['update_type'] == 'br_valid') and order_line['new_shelf_price'] and order_line['barcode'][:4] not in noprint_list:
try:
tools_url = settings.TOOLS_SERVER + '/products/label_print/'
tools_url += str(order_line['product_tmpl_id']) + '/'
......@@ -235,6 +243,7 @@ def update_orders(request):
# Remove order's group
try:
if os.path.exists('temp/grouped_order.json'):
with open('temp/grouped_order.json', 'r') as json_file:
saved_groups = json.load(json_file)
......@@ -292,6 +301,7 @@ def save_error_report(request):
orders_partner = orders_partner + ', '
orders_partner = orders_partner + order['partner'] + ' du ' + order['date_order']
# If group of orders
if len(data['orders']) > 1 :
temp_group_file_name = "temp/" + orders_name + "_rapport-reception_temp.xlsx"
......@@ -309,6 +319,7 @@ def save_error_report(request):
data['orders'].append(group_order)
# Save qties & comments after step 1
if data['update_type'] == 'qty_valid':
for order in data['orders']:
......@@ -328,8 +339,8 @@ def save_error_report(request):
# If in group add group name
if len(data['orders']) > 1 :
ws.append( ['group', orders_name] )
try:
if 'updated_products' in order:
for product in order['updated_products']:
# Don't store products with same qties
if product['old_qty'] != product['product_qty']:
......@@ -351,10 +362,9 @@ def save_error_report(request):
product['product_qty'],
product['price_unit'],
supplier_shortage] )
except:
# no updated products, do nothing
pass
except Exception as exp:
print("Error while updating products")
print(exp)
if ('user_comments' in data) and data['user_comments'] != "":
ws.append( ['commentaire', data['user_comments']] )
else:
......@@ -363,6 +373,8 @@ def save_error_report(request):
# Save file
wb.save(filename=order['temp_file_name'])
# Create report with data from steps 1 & 2
else:
for order in data['orders']:
......@@ -397,7 +409,6 @@ def save_error_report(request):
os.remove(order['temp_file_name'])
except:
data_comment_s1 = "Rapport de la première étape absent !"
# Add data from step 2
data_full = []
error_total = 0
......@@ -409,6 +420,7 @@ def save_error_report(request):
# Concatenate products info from each step
try:
if "updated_products" in order:
for product in order['updated_products']:
if 'supplier_code' in product:
supplier_code = str(product['supplier_code'])
......@@ -453,10 +465,10 @@ def save_error_report(request):
error_total_abs += abs(item['error_line'])
data_full.append(item)
except:
except Exception as exp:
# no updated products, do nothing
pass
print("Error while updating products")
print(exp)
# Add remaining products, the ones edited only in step 1
for product in data_qties.values():
item = {
......@@ -486,7 +498,6 @@ def save_error_report(request):
wb = Workbook()
ws = wb.active
ws.title = "Commande " + order['name']
# Group
if 'group_ids' in order :
ws.append( ['Rapport de réception d\'un groupe de commandes'] )
......@@ -528,7 +539,6 @@ def save_error_report(request):
round(product['expected_amount'], 2),
round(product['error_line'], 2),
product['supplier_shortage']] )
ws.append( [] )
ws.append( ['Montant total de l\'erreur :', '', '', '', '', '', '', '', round(error_total, 2)] )
ws.append( ['Montant total en valeur absolue :', '', '', '', '', '', '', '', round(error_total_abs, 2)] )
......@@ -563,7 +573,6 @@ def save_error_report(request):
top_left_cell.alignment = Alignment(vertical="top")
top_left_cell = ws['B'+str(merge_begin)]
top_left_cell.alignment = Alignment(vertical="top")
# "Auto fit" columns width to content
for column_cells in ws.columns:
length = max(len(as_text(cell.value)) for cell in column_cells)
......@@ -572,23 +581,23 @@ def save_error_report(request):
length = 20
ws.column_dimensions[column_cells[3].column_letter].width = length
# Save file
fileName = "temp/" + order['name'] + "_rapport-reception.xlsx"
try:
wb.save(filename=fileName)
except Exception as exp:
print("Error while saving file %s"%fileName)
print(str(exp))
#Attach file to order
if 'group_ids' in order : # group report
# Attach group report to each order
for group_item_id in order['group_ids'] :
m = CagetteReception(group_item_id)
m.attach_file(fileName, False)
os.remove(fileName)
else:
m = CagetteReception(order['id'])
m.attach_file(fileName)
return JsonResponse("ok", safe=False)
def reception_FAQ(request):
......
Utilisé pour stocker de façon temporaire des données par plusieurs modules
......@@ -120,9 +120,7 @@
<hr />
<p class="txtleft">
Ici, vous pouvez signaler toute anomalie lors d'une réception, les produits non commandés, cassés ou pourris.
Merci d'indiquer un maximum d'informations, le nom du produit et son code barre.
Dans le cas de produits déteriorés, merci d'envoyer une photo avec votre téléphone à <strong>{{RECEPTION_PB_EMAIL}}</strong>
{{RECEPTION_PB}}
</p>
<br>
<textarea id="error_report"></textarea>
......
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