Add DPD protocol import

master
informatic 2020-04-21 08:37:32 +02:00
parent 0cb51988a1
commit ec7705761c
4 changed files with 101 additions and 21 deletions

View File

@ -10,7 +10,7 @@ RUN apk add --no-cache \
# psycopg2 needs some extra build tools and headers. Install them and build in a
# single step in order not to pollute Docker layers
RUN apk add --no-cache --virtual .build-deps gcc python3-dev musl-dev postgresql-dev libffi-dev && \
pip3 install --no-cache-dir psycopg2==2.8.4 pycparser==2.20 cffi==1.14.0 bcrypt==3.1.7 && \
pip3 install --no-cache-dir psycopg2==2.8.4 pycparser==2.20 cffi==1.14.0 bcrypt==3.1.7 pycryptodome==3.9.7 && \
apk del --no-cache .build-deps
RUN apk add --no-cache py3-pillow cairo pango glib font-noto gdk-pixbuf-dev

View File

@ -2,8 +2,9 @@ import enum
import io
import datetime
import csv
from flask import redirect, flash, request, url_for, make_response, current_app
from flask import redirect, flash, request, url_for, make_response, current_app, session
import flask_admin
import pdfplumber
from formity.extensions import admin, db, ModelView, ModelViewHighSecurity, AdminSecurityMixin
from wtforms import TextAreaField, validators
from formity.models import FaceshieldRequest, RequestChange, Status, PostalCode, ExternalUser
@ -138,6 +139,58 @@ class FaceshieldRequestAdmin(ModelView):
model = self.get_one(request.args.get('id'))
return self.render('label.html', models=[model])
@flask_admin.expose('/import-dpd', methods=['POST', 'GET'])
def dpd_import(self):
if request.method == 'POST':
# check if the post request has the file part
if request.form.get('accept') == '1':
changed = 0
for k, v in session.get('dpd-import', {}).items():
m = FaceshieldRequest.query.filter(FaceshieldRequest.id == k).first()
if not m:
flash('Request #{} not found'.format(k), 'warning')
continue
m.shipping_id = ','.join(v)
m.shipping_provider = 'xbs'
changed += 1
db.session.commit()
flash('{} requests changed'.format(changed), 'info')
session.pop('dpd-import')
return redirect(request.url)
if 'file' not in request.files:
flash('No file uploaded', 'error')
return redirect(request.url)
file = request.files['file']
if file.filename == '':
flash('No selected file', 'error')
return redirect(request.url)
p = pdfplumber.load(file.stream)
data = self.parse_dpd(p)
session['dpd-import'] = {k: list(v) for k, v in data.items()}
return self.render('admin/dpd_pdf_import.html', data=session['dpd-import'])
return self.render('admin/dpd_pdf_import.html')
def parse_dpd(self, pdf):
data = {}
for page in pdf.pages:
table = page.extract_table()
if table[0] != [None, None, None, None, 'MIEJSCE DORĘCZENIA PACZKI', None, None, None, None, None]:
raise Exception('Invalid header (1/2)')
if table[1] != ['LP', 'Numkat', 'NUMER PACZKI', 'NUMER REFERENCYJNY\n( np. numer faktury, zamówienia itp.)', 'OPIS', 'Odbiorca', 'Wartość\nprzesyłki', 'KWOTA\nCOD PLN', 'Waga dekl.\n(kg)', 'Zawartość']:
raise Exception('Invalid header (2/2)')
for row in table[2:]:
ref = row[3].split('/')[0]
tracking = row[2]
if ref not in data:
data[ref] = set()
data[ref].add(tracking)
return data
def bulk_status_change(self, ids, status):
try:
query = self.get_query().filter(FaceshieldRequest.id.in_(ids))
@ -283,27 +336,28 @@ class FaceshieldRequestAdmin(ModelView):
writer.writeheader()
config = current_app.config
for row in models:
writer.writerow({
'NAZWA NADAWCY': config['SHIPPING_SENDER_NAME'],
'OSOBA KONTAKTOWA NADAWCA': config['SHIPPING_SENDER_NAME2'],
'ULICA NADAWCA': '%s %s' % (config['SHIPPING_SENDER_STREET'], config['SHIPPING_SENDER_NUMBER']),
'KOD POCZTOWY NADAWCA': config['SHIPPING_SENDER_POSTALCODE'],
'MIASTO NADAWCA': config['SHIPPING_SENDER_CITY'],
'TELEFON KONTAKTOWY NADAWCA ': config['SHIPPING_SENDER_PHONE_NUMBER'],
for label_id in range(row.label_count):
writer.writerow({
'NAZWA NADAWCY': config['SHIPPING_SENDER_NAME'],
'OSOBA KONTAKTOWA NADAWCA': config['SHIPPING_SENDER_NAME2'],
'ULICA NADAWCA': '%s %s' % (config['SHIPPING_SENDER_STREET'], config['SHIPPING_SENDER_NUMBER']),
'KOD POCZTOWY NADAWCA': config['SHIPPING_SENDER_POSTALCODE'],
'MIASTO NADAWCA': config['SHIPPING_SENDER_CITY'],
'TELEFON KONTAKTOWY NADAWCA ': config['SHIPPING_SENDER_PHONE_NUMBER'],
'NAZWA ODBIORCA': row.shipping_name,
'OSOBA KONTAKTOWA ODBIORCA': row.full_name,
'TELEFON KONTAKTOWYODBIORCA': row.phone_number,
'ULICA ODBIORCA': row.shipping_street,
'KOD POCZTOWY ODBIORCA': row.shipping_postalcode,
'MIASTO ODBIORCA': row.shipping_city,
'NAZWA ODBIORCA': row.shipping_name,
'OSOBA KONTAKTOWA ODBIORCA': row.full_name,
'TELEFON KONTAKTOWYODBIORCA': row.phone_number,
'ULICA ODBIORCA': row.shipping_street,
'KOD POCZTOWY ODBIORCA': row.shipping_postalcode,
'MIASTO ODBIORCA': row.shipping_city,
# TODO kartony?
'WAGA': 12,
'ILOŚĆ PACZEK': 1,
'NR REFERENCYJNY 1': row.id,
'ZAWARTOŚĆ': 'przyłbice dla medyków',
})
# TODO kartony?
'WAGA': 20,
'ILOŚĆ PACZEK': 1,
'NR REFERENCYJNY 1': '%s/%s/%s' % (row.id, label_id + 1, row.label_count),
'ZAWARTOŚĆ': 'przyłbice dla medyków',
})
row.changelog.append(RequestChange(
remarks='included on XBS export (%s)' % (fname,),

View File

@ -29,10 +29,13 @@ Mako==1.1.2
MarkupSafe==1.1.1
marshmallow==3.5.1
oauthlib==2.1.0
pdfminer.six==20200104
pdfplumber==0.5.19
Pillow==6.2.1
prometheus-client==0.7.1
prometheus-flask-exporter==0.13.0
pycparser==2.20
pycryptodome==3.9.7
Pyphen==0.9.5
python-dateutil==2.8.1
python-dotenv==0.12.0
@ -42,9 +45,12 @@ redis==3.4.1
requests==2.23.0
requests-oauthlib==1.3.0
six==1.14.0
sortedcontainers==2.1.0
SQLAlchemy==1.3.15
tinycss2==1.0.2
unicodecsv==0.14.1
urllib3==1.25.8
Wand==0.5.9
WeasyPrint==51
webencodings==0.5.1
Werkzeug==0.16.1

View File

@ -0,0 +1,20 @@
{% extends "admin/master.html" %}
{% block body %}
<h2 class="page-header">DPD Protocol Import</h2>
<form method=post enctype=multipart/form-data>
<input type=file name=file>
<input type=submit value=Upload>
</form>
{% if data is defined %}
<h3>Imported data:</h3>
<form method="post">
<table class="table">
{% for k, v in data.items() %}
<tr><td>{{ k }}</td><td>{{ v }}</td></tr>
{% endfor %}
</table>
<input type="hidden" name="accept" value="1" />
<button class="btn btn-primary">Accept</button>
</form>
{% endif %}
{% endblock %}