fixed crud list
fixed payments upload -a
This commit is contained in:
+1
-1
@@ -7,7 +7,7 @@ from payments.models import Payment
|
||||
class PaymentCreateForm(ModelForm):
|
||||
class Meta:
|
||||
model = Payment
|
||||
fields = ['total_amount', 'company', 'description']
|
||||
fields = ['company', 'total_amount', 'description']
|
||||
widgets = {
|
||||
'containers': CheckboxSelectMultiple(),
|
||||
}
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
import base64
|
||||
import hashlib
|
||||
import hmac
|
||||
import urllib.parse
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
import requests
|
||||
|
||||
from DepoT.settings import env
|
||||
|
||||
|
||||
class EPay:
|
||||
payment_types = {
|
||||
"pay_credit_card": "credit_paydirect",
|
||||
"pay_epay": "paylogin",
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def encode_message(message):
|
||||
encoded_data = base64.b64encode(message.encode("utf-8")).decode("utf-8")
|
||||
secret_key = env("EPAY_SECURITY_KEY")
|
||||
checksum = hmac.new(
|
||||
secret_key.encode("utf-8"), encoded_data.encode("utf-8"), hashlib.sha1
|
||||
).hexdigest()
|
||||
return encoded_data, checksum
|
||||
|
||||
@classmethod
|
||||
def generate_urls(self, invoice, amount):
|
||||
client_id = env("EPAY_CLIENT_ID")
|
||||
description = f"Invoice number: {invoice} with amount of {amount}"
|
||||
currency = "BGN"
|
||||
expiry = (
|
||||
datetime.today() + timedelta(days=int(env("INVOICE_EXPIRE_PERIOD")))
|
||||
).strftime("%d.%m.%Y")
|
||||
|
||||
if amount == 0:
|
||||
amount = 1000
|
||||
|
||||
message = f"MIN={client_id}\nINVOICE={invoice}\nAMOUNT={amount}\nCURRENCY={currency}\nEXP_TIME={expiry}\nDESCR={description}"
|
||||
encoded_data, checksum = EPay.encode_message(message)
|
||||
result = {}
|
||||
for pay_type, keyword in EPay.payment_types.items():
|
||||
url = f"https://demo.epay.bg/?PAGE={keyword}&ENCODED={urllib.parse.quote(encoded_data)}&CHECKSUM={urllib.parse.quote(checksum)}"
|
||||
result[pay_type] = url
|
||||
return result
|
||||
|
||||
@staticmethod
|
||||
def payment_result(encoded_data, checksum_received):
|
||||
secret_key = env("EPAY_SECURITY_KEY")
|
||||
decoded_data = base64.b64decode(encoded_data).decode("utf-8")
|
||||
checksum_calculated = hmac.new(
|
||||
secret_key.encode("utf-8"), encoded_data.encode("utf-8"), hashlib.sha1
|
||||
).hexdigest()
|
||||
checksum_result = checksum_calculated == checksum_received
|
||||
|
||||
fields = decoded_data.split(":")
|
||||
fields_dict = {}
|
||||
for field in fields:
|
||||
try:
|
||||
name, value = field.split("=")
|
||||
except ValueError:
|
||||
print(fields)
|
||||
print(field)
|
||||
|
||||
fields_dict[name] = value
|
||||
|
||||
return fields_dict, checksum_result
|
||||
|
||||
@staticmethod
|
||||
def send_response(encoded_data, checksum):
|
||||
url = f"https://demo.epay.bg/?ENCODED={urllib.parse.quote(encoded_data)}&CHECKSUM={urllib.parse.quote(checksum)}"
|
||||
print(url)
|
||||
res = requests.post(url)
|
||||
|
||||
@staticmethod
|
||||
def send_ok(invoice):
|
||||
message = f"INVOICE={invoice}:STATUS=OK"
|
||||
encoded_data, checksum = EPay.encode_message(message)
|
||||
print(f"OK {invoice}")
|
||||
EPay.send_response(encoded_data, checksum)
|
||||
|
||||
@staticmethod
|
||||
def send_no(invoice):
|
||||
message = f"INVOICE={invoice}:STATUS=NO"
|
||||
encoded_data, checksum = EPay.encode_message(message)
|
||||
print(f"NO {invoice}")
|
||||
EPay.send_response(encoded_data, checksum)
|
||||
|
||||
@staticmethod
|
||||
def send_err(invoice):
|
||||
message = f"INVOICE={invoice}:STATUS=ERR:ERR=BAD_CHECKSUM"
|
||||
encoded_data, checksum = EPay.encode_message(message)
|
||||
print(f"ERR {invoice}")
|
||||
EPay.send_response(encoded_data, checksum)
|
||||
|
||||
+2
-1
@@ -1,7 +1,8 @@
|
||||
from django.urls import path
|
||||
|
||||
from payments.views import PaymentCreateView
|
||||
from payments.views import PaymentCreateView, some_view
|
||||
|
||||
urlpatterns = [
|
||||
path("create/", PaymentCreateView.as_view(), name="payments_create"),
|
||||
path('invoice/', some_view, name='payments_invoice'),
|
||||
]
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
from django.db.models import Q
|
||||
|
||||
from payments.models import ContainerTariffPeriod, AdditionalFees
|
||||
|
||||
|
||||
def calculate_charges(container):
|
||||
days = (container.expedited_on.date() - container.received_on.date()).days + 1
|
||||
total = 0
|
||||
|
||||
size = '20' if container.container_type.length == 20 else '40'
|
||||
|
||||
tariff = ContainerTariffPeriod.objects.get(
|
||||
Q(to_days__gt=days) | Q(to_days__isnull=True),
|
||||
container_size=size,
|
||||
from_days__lte=days,
|
||||
)
|
||||
|
||||
fees = AdditionalFees.objects.first()
|
||||
storage_charge = days * float(tariff.daily_rate)
|
||||
|
||||
if container.container_type.container_type == 'reefer':
|
||||
storage_charge += days * float(fees.reefer_daily_supplement)
|
||||
|
||||
if container.swept:
|
||||
total += float(fees.sweeping_fee)
|
||||
if container.washed:
|
||||
total += float(fees.fumigation_fee)
|
||||
|
||||
total += storage_charge
|
||||
|
||||
return {
|
||||
'days': days,
|
||||
'storage_charge': storage_charge,
|
||||
'services_charge': total - storage_charge,
|
||||
'total': total,
|
||||
}
|
||||
|
||||
+193
-7
@@ -1,25 +1,72 @@
|
||||
from datetime import datetime
|
||||
|
||||
from django.db.models import Sum
|
||||
from django.shortcuts import render
|
||||
from django.urls import reverse_lazy
|
||||
from django.views.generic import ListView, CreateView
|
||||
from reportlab.lib import colors
|
||||
from reportlab.lib.pagesizes import A4
|
||||
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
|
||||
from reportlab.platypus import Table, TableStyle, Spacer, Paragraph, SimpleDocTemplate
|
||||
|
||||
from common.models import CompanyModel
|
||||
from common.utils.utils import send_test_email
|
||||
from containers.models import Container
|
||||
from payments.forms import PaymentCreateForm
|
||||
from payments.models import Payment
|
||||
from payments.models import Payment, PaymentItem
|
||||
from payments.services import EPay
|
||||
from payments.utils import calculate_charges
|
||||
|
||||
import io
|
||||
from django.http import FileResponse, HttpResponse, response
|
||||
from reportlab.pdfgen import canvas
|
||||
|
||||
# Create your views here.
|
||||
class PaymentCreateView(CreateView):
|
||||
model = Payment
|
||||
form_class = PaymentCreateForm
|
||||
template_name = 'employee/payment-create.html'
|
||||
success_url = reverse_lazy('payment-list')
|
||||
success_url = reverse_lazy('not_paid')
|
||||
|
||||
def form_valid(self, form):
|
||||
container_ids = self.request.POST.getlist('containers')
|
||||
|
||||
last_payment = Payment.objects.order_by('-invoice_number').first()
|
||||
today = datetime.now().strftime('%Y%m%d')
|
||||
|
||||
if last_payment and last_payment.invoice_number.startswith(f'INV-{today}'):
|
||||
last_number = int(last_payment.invoice_number.split('-')[-1])
|
||||
new_number = str(last_number + 1).zfill(4)
|
||||
else:
|
||||
new_number = '0001'
|
||||
|
||||
invoice_number = f'INV-{today}-{new_number}'
|
||||
|
||||
payment = form.save(commit=False)
|
||||
payment.invoice_number = invoice_number
|
||||
payment.created_by = self.request.user
|
||||
payment.updated_by = self.request.user
|
||||
payment.total_amount = 0
|
||||
payment.save()
|
||||
payment.containers.set(container_ids)
|
||||
|
||||
container_ids = self.request.POST.getlist('containers')
|
||||
containers = Container.objects.filter(id__in=container_ids)
|
||||
for container in containers:
|
||||
charges = calculate_charges(container)
|
||||
payment.total_amount += charges['total']
|
||||
PaymentItem.objects.create(
|
||||
payment=payment,
|
||||
container=container,
|
||||
amount=charges['total'] # Using total charge for the container
|
||||
)
|
||||
|
||||
# 0000000000000000000000000000000000#
|
||||
urls = EPay.generate_urls(payment.invoice_number, payment.total_amount)
|
||||
print("Generated URLs:", urls)
|
||||
payment.save()
|
||||
send_test_email('kikimor@gmail.com', urls) # invoice and
|
||||
# 0000000000000000000000000000000000#
|
||||
|
||||
|
||||
return super().form_valid(form)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
@@ -42,6 +89,145 @@ class PaymentCreateView(CreateView):
|
||||
company_pk = self.request.GET.get('company', '')
|
||||
form.fields['company'].initial = company_pk
|
||||
|
||||
# container_ids = [int(id) for id in container_ids if id.strip().isdigit()]
|
||||
# form.fields['containers'].initial = container_ids
|
||||
return form
|
||||
container_ids = self.request.GET.get('containers', '').split(',')
|
||||
container_ids = [int(_id) for _id in container_ids if _id.strip().isdigit()]
|
||||
|
||||
total_charges = {}
|
||||
if container_ids:
|
||||
containers = Container.objects.filter(
|
||||
id__in=container_ids,
|
||||
expedited=True,
|
||||
payment_containers__isnull=True
|
||||
)
|
||||
for container in containers:
|
||||
charges = calculate_charges(container)
|
||||
total_charges['days'] = total_charges.get('days', 0) + charges.get('days', 0)
|
||||
total_charges['storage_charge'] = total_charges.get('storage_charge', 0) + charges.get('storage_charge', 0)
|
||||
total_charges['services_charge'] = total_charges.get('services_charge', 0) + charges.get('services_charge', 0)
|
||||
total_charges['total'] = total_charges.get('total', 0) + charges.get('total', 0)
|
||||
form.fields['total_amount'].initial = total_charges['total']
|
||||
return form
|
||||
|
||||
def some_view(request):
|
||||
buffer = io.BytesIO()
|
||||
doc = SimpleDocTemplate(buffer, pagesize=A4)
|
||||
story = []
|
||||
styles = getSampleStyleSheet()
|
||||
|
||||
# Custom styles
|
||||
styles.add(ParagraphStyle(
|
||||
name='RightAlign',
|
||||
parent=styles['Normal'],
|
||||
alignment=2 # right alignment
|
||||
))
|
||||
|
||||
# Header data
|
||||
depot_data = [
|
||||
['ABC Depot Ltd.'],
|
||||
['123 Depot Street'],
|
||||
['Sofia, Bulgaria'],
|
||||
['VAT: BG123456789'],
|
||||
['Phone: +359 2 123 4567']
|
||||
]
|
||||
|
||||
customer_data = [
|
||||
['Customer Company Ltd.'],
|
||||
['456 Customer Ave.'],
|
||||
['London, UK'],
|
||||
['VAT: GB987654321'],
|
||||
['Contact: John Doe']
|
||||
]
|
||||
|
||||
# Create header table
|
||||
header_data = [[
|
||||
Table(depot_data, colWidths=[200]),
|
||||
Table(customer_data, colWidths=[200])
|
||||
]]
|
||||
header_table = Table(header_data, colWidths=[250, 250])
|
||||
header_table.setStyle(TableStyle([
|
||||
('ALIGN', (0, 0), (-1, -1), 'LEFT'),
|
||||
('VALIGN', (0, 0), (-1, -1), 'TOP'),
|
||||
]))
|
||||
story.append(header_table)
|
||||
story.append(Spacer(1, 30))
|
||||
|
||||
# Invoice title and number
|
||||
story.append(Paragraph('INVOICE', styles['Heading1']))
|
||||
story.append(Paragraph('Invoice No: INV-20240220-0001', styles['Normal']))
|
||||
story.append(Paragraph('Date: 20.02.2024', styles['Normal']))
|
||||
story.append(Spacer(1, 20))
|
||||
|
||||
# Invoice table data
|
||||
table_data = [
|
||||
['Container Type', 'Days', 'Swept', 'Washed', 'Amount'],
|
||||
['20\' Container', '15', 'Yes', 'No', '€450.00'],
|
||||
['40\' Container', '10', 'Yes', 'Yes', '€750.00'],
|
||||
]
|
||||
|
||||
# Create invoice table
|
||||
invoice_table = Table(table_data, colWidths=[120, 80, 80, 80, 100])
|
||||
invoice_table.setStyle(TableStyle([
|
||||
('BACKGROUND', (0, 0), (-1, 0), colors.grey),
|
||||
('TEXTCOLOR', (0, 0), (-1, 0), colors.whitesmoke),
|
||||
('ALIGN', (0, 0), (-1, -1), 'CENTER'),
|
||||
('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'),
|
||||
('FONTSIZE', (0, 0), (-1, 0), 12),
|
||||
('BOTTOMPADDING', (0, 0), (-1, 0), 12),
|
||||
('GRID', (0, 0), (-1, -1), 1, colors.black),
|
||||
('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
|
||||
]))
|
||||
story.append(invoice_table)
|
||||
story.append(Spacer(1, 20))
|
||||
|
||||
# Total amount
|
||||
total_text = f'Total Amount: €1,200.00'
|
||||
story.append(Paragraph(total_text, styles['RightAlign']))
|
||||
|
||||
# Build PDF
|
||||
doc.build(story, onFirstPage=add_watermark)
|
||||
pdf = buffer.getvalue()
|
||||
buffer.close()
|
||||
|
||||
# Create response
|
||||
response = HttpResponse(content_type='application/pdf')
|
||||
response['Content-Disposition'] = 'inline; filename="invoice.pdf"'
|
||||
response.write(pdf)
|
||||
return response
|
||||
|
||||
|
||||
def add_watermark(canvas, doc):
|
||||
canvas.saveState()
|
||||
canvas.setFillColorRGB(0.9, 0.9, 0.9)
|
||||
canvas.setFont('Helvetica', 80)
|
||||
canvas.rotate(45)
|
||||
canvas.drawString(200, 000, 'ORIGINAL')
|
||||
canvas.restoreState()
|
||||
|
||||
return response
|
||||
|
||||
|
||||
def on_payment_result(encoded, checksum):
|
||||
fields_dict, checksum_result = EPay.payment_result(encoded, checksum)
|
||||
status = fields_dict["STATUS"]
|
||||
invoice = fields_dict["INVOICE"]
|
||||
if not checksum_result:
|
||||
return f"INVOICE={invoice}:STATUS=ERR"
|
||||
|
||||
payment = Payment.objects.get(invoice_number=invoice)
|
||||
if not payment:
|
||||
return f"INVOICE={invoice}:STATUS=NO"
|
||||
|
||||
match status:
|
||||
case "PAID":
|
||||
payment.status = "paid"
|
||||
payment.paid_on = datetime.now()
|
||||
payment.pay_time = fields_dict["PAY_TIME"]
|
||||
payment.pay_stan = fields_dict["STAN"]
|
||||
payment.pay_bcode = fields_dict["BCODE"]
|
||||
|
||||
case "DENIED":
|
||||
payment.status = "denied"
|
||||
case "EXPIRED":
|
||||
payment.status = "expired"
|
||||
payment.save()
|
||||
return f"INVOICE={invoice}:STATUS=OK"
|
||||
Reference in New Issue
Block a user