New changes.
@ -0,0 +1,18 @@
|
||||
# Generated by Django 5.0.4 on 2024-05-10 06:40
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('billing', '0051_alter_orderpayment_amount'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='orderstatus',
|
||||
name='status',
|
||||
field=models.CharField(choices=[('Completed', 'Completed'), ('Pending', 'Pending'), ('Failed', 'Failed'), ('Cancelled', 'Cancelled'), ('In Progress', 'In Progress')], default='Pending', max_length=200),
|
||||
),
|
||||
]
|
@ -0,0 +1,35 @@
|
||||
{% load static %}
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Osina</title>
|
||||
|
||||
<link rel="stylesheet" type="text/css" href='{% static "dist/output.css" %}'>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css">
|
||||
</head>
|
||||
|
||||
<body class="font-poppinsLight">
|
||||
<form id="hiddenContent" method="POST" action="">
|
||||
{% csrf_token %}
|
||||
<h1 class="text-secondosiblue text-2xl font-semibold text-center">Update Order Status</h1>
|
||||
|
||||
<select name="" id="" class="w-full h-[50px] py-1 px-3 border border-gray-300 outline-none rounded-md mt-4">
|
||||
<option value="Completed">Completed</option>
|
||||
<option value="Pending">Pending</option>
|
||||
<option value="Failed">Failed</option>
|
||||
<option value="Cancelled">Cancelled</option>
|
||||
</select>
|
||||
|
||||
<div class="w-full flex justify-center items-center mt-4">
|
||||
<button type="submit"
|
||||
class="w-fit bg-osiblue border border-osiblue rounded-md text-white text-xl px-5 py-1 hover:bg-white hover:text-osiblue">Save</button>
|
||||
</div>
|
||||
</form>
|
||||
</body>
|
||||
|
||||
</html>
|
@ -0,0 +1,20 @@
|
||||
from django.urls import path
|
||||
from . import views
|
||||
|
||||
|
||||
urlpatterns = [
|
||||
path('whish-payment/<int:payment_id>/', views.whish_payment, name='whishpayment'),
|
||||
path('cash-payment/<int:payment_id>/', views.cash_payment, name='cashpayment'),
|
||||
|
||||
path('checkout/<int:payment_id>/', views.card_payment, name='cardpayment'),
|
||||
path('initiate-payment-checkout/', views.initiate_payment_checkout, name='initiatepaymentcheckout'),
|
||||
|
||||
|
||||
path('buy-now/<int:item_id>/', views.buy_now, name='buynow'),
|
||||
path('buy-now-checkout/', views.buy_now_checkout, name='buynowcheckout'),
|
||||
path('check-order-status/<str:merchant_id>/<str:order_id>/', views.check_order_status, name='check_order_status'),
|
||||
|
||||
|
||||
path('payment/osimenu-basic/', views.buy_free_osimenu, name='buyfreeosimenu'),
|
||||
path('payment/osicard-basic/', views.buy_free_osicard, name='buyfreeosicard'),
|
||||
]
|
@ -0,0 +1,354 @@
|
||||
from django.shortcuts import render, get_object_or_404
|
||||
from customercore.decorators import *
|
||||
from customercore.models import *
|
||||
from billing.add.views import *
|
||||
from django.http import JsonResponse
|
||||
import requests
|
||||
import json
|
||||
import base64
|
||||
import json
|
||||
import random
|
||||
import string
|
||||
|
||||
|
||||
def basic_auth_header(username, password):
|
||||
credentials = f"merchant.{username}:{password}"
|
||||
encoded_credentials = base64.b64encode(credentials.encode('utf-8')).decode('utf-8')
|
||||
return f"Basic {encoded_credentials}"
|
||||
|
||||
|
||||
|
||||
def whish_payment(request, payment_id):
|
||||
payment = get_object_or_404(OrderPayment, id = payment_id)
|
||||
|
||||
context = {
|
||||
'payment' : payment,
|
||||
}
|
||||
|
||||
return render(request, 'payment_pages/whish-payment.html', context)
|
||||
|
||||
|
||||
def cash_payment(request, payment_id):
|
||||
payment = get_object_or_404(OrderPayment, id = payment_id)
|
||||
|
||||
context = {
|
||||
'payment' : payment,
|
||||
}
|
||||
|
||||
return render(request, 'payment_pages/cash-payment.html', context)
|
||||
|
||||
|
||||
|
||||
|
||||
def card_payment(request, payment_id):
|
||||
payment = get_object_or_404(OrderPayment, id = payment_id)
|
||||
|
||||
context = {
|
||||
'payment' : payment,
|
||||
}
|
||||
|
||||
return render(request, 'payment_pages/card-payment.html', context)
|
||||
|
||||
|
||||
@customer_login_required
|
||||
def initiate_payment_checkout(request):
|
||||
api_username = 'merchant.TEST06127800'
|
||||
api_password = '37846250a67c70e7fe9f82cf6ca81f93'
|
||||
merchant_id = 'TEST06127800'
|
||||
merchant_name = 'Ositcom Sal'
|
||||
|
||||
customer = request.user.customerprofile
|
||||
|
||||
data = json.loads(request.body)
|
||||
payment_id = data.get('payment_id')
|
||||
|
||||
payment = get_object_or_404(OrderPayment, id=payment_id)
|
||||
|
||||
|
||||
order = payment.order
|
||||
order_id = order.order_id
|
||||
|
||||
price = order.get_cart_total
|
||||
|
||||
|
||||
payload = {
|
||||
'apiOperation': 'INITIATE_CHECKOUT',
|
||||
'apiUsername': api_username,
|
||||
'apiPassword': api_password,
|
||||
'merchant': merchant_id,
|
||||
'interaction.operation': 'PURCHASE',
|
||||
'interaction.merchant.name': merchant_name,
|
||||
'order.id': order_id,
|
||||
'order.amount': price,
|
||||
'order.currency': 'USD',
|
||||
'order.description': 'description_of_order',
|
||||
'order.notificationUrl' : 'https://newosina.osinode.com/webhooks/',
|
||||
'interaction.returnUrl' : f"https://newosina.osinode.com/check-order-status/{merchant_id}/{order_id}/"
|
||||
}
|
||||
|
||||
try:
|
||||
response = requests.post('https://creditlibanais-netcommerce.gateway.mastercard.com/api/nvp/version/78', data=payload)
|
||||
|
||||
print('Response Content:', response.text)
|
||||
|
||||
if response.status_code == 200:
|
||||
response_data = response.text
|
||||
parsed_data = dict(item.split('=') for item in response_data.split('&'))
|
||||
session_id = parsed_data.get('session.id')
|
||||
return JsonResponse({'session_id': session_id}, status=200)
|
||||
|
||||
else:
|
||||
print('Response Status Code:', response.status_code)
|
||||
return JsonResponse({'error': 'Failed to initiate checkout'}, status=500)
|
||||
except Exception as e:
|
||||
print('Exception:', e)
|
||||
return JsonResponse({'error': 'Internal Server Error'}, status=500)
|
||||
|
||||
|
||||
|
||||
@customer_login_required
|
||||
def buy_now(request, item_id):
|
||||
item = get_object_or_404(Item, id=item_id)
|
||||
cycles = RecurringCycle.objects.filter(item = item)
|
||||
|
||||
selected_cycle = None
|
||||
|
||||
context = {
|
||||
'item' : item,
|
||||
'cycles' : cycles,
|
||||
'selected_cycle': selected_cycle,
|
||||
}
|
||||
|
||||
return render(request, 'payment_pages/buy-now.html', context)
|
||||
|
||||
|
||||
|
||||
@customer_login_required
|
||||
def buy_now_checkout(request):
|
||||
api_username = 'merchant.TEST06127800'
|
||||
api_password = '37846250a67c70e7fe9f82cf6ca81f93'
|
||||
merchant_id = 'TEST06127800'
|
||||
merchant_name = 'Ositcom Sal'
|
||||
|
||||
customer = request.user.customerprofile
|
||||
|
||||
data = json.loads(request.body)
|
||||
item_id = data.get('item_id')
|
||||
cycle_id = data.get('cycle_id')
|
||||
|
||||
item = Item.objects.get(id=item_id)
|
||||
|
||||
cycle = RecurringCycle.objects.get(id = cycle_id)
|
||||
price = cycle.cycle_price
|
||||
|
||||
|
||||
existing_order = Order.objects.filter(customer=customer, orderstatus__isnull=True).first()
|
||||
|
||||
|
||||
if existing_order:
|
||||
existing_order.orderitem_set.all().delete()
|
||||
order = existing_order
|
||||
else:
|
||||
order = Order.objects.create(customer=customer)
|
||||
|
||||
order.save()
|
||||
order_id = order.order_id
|
||||
|
||||
|
||||
order_item = OrderItem.objects.create(order=order, item=item, end_at = datetime.now() + timedelta(days=(cycle.months * 30)))
|
||||
order_item.save()
|
||||
|
||||
|
||||
payload = {
|
||||
'apiOperation': 'INITIATE_CHECKOUT',
|
||||
'apiUsername': api_username,
|
||||
'apiPassword': api_password,
|
||||
'merchant': merchant_id,
|
||||
'interaction.operation': 'PURCHASE',
|
||||
'interaction.merchant.name': merchant_name,
|
||||
'order.id': order_id,
|
||||
'order.amount': price,
|
||||
'order.currency': 'USD',
|
||||
'order.description': 'description_of_order',
|
||||
'order.notificationUrl' : 'https://newosina.osinode.com/webhooks/',
|
||||
'interaction.returnUrl' : f"https://osina.ositcom.com/check-order-status/{merchant_id}/{order_id}/"
|
||||
}
|
||||
|
||||
try:
|
||||
response = requests.post('https://creditlibanais-netcommerce.gateway.mastercard.com/api/nvp/version/78', data=payload)
|
||||
|
||||
print('Response Content:', response.text)
|
||||
|
||||
if response.status_code == 200:
|
||||
response_data = response.text
|
||||
parsed_data = dict(item.split('=') for item in response_data.split('&'))
|
||||
session_id = parsed_data.get('session.id')
|
||||
return JsonResponse({'session_id': session_id}, status=200)
|
||||
|
||||
else:
|
||||
print('Response Status Code:', response.status_code)
|
||||
return JsonResponse({'error': 'Failed to initiate checkout'}, status=500)
|
||||
except Exception as e:
|
||||
print('Exception:', e)
|
||||
return JsonResponse({'error': 'Internal Server Error'}, status=500)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def check_order_status(request, merchant_id, order_id):
|
||||
api_password = '37846250a67c70e7fe9f82cf6ca81f93'
|
||||
url = f"https://creditlibanais-netcommerce.gateway.mastercard.com/api/rest/version/78/merchant/{merchant_id}/order/{order_id}"
|
||||
order = Order.objects.get(order_id=order_id)
|
||||
|
||||
headers = {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': basic_auth_header(merchant_id, api_password)
|
||||
}
|
||||
|
||||
try:
|
||||
response = requests.get(url, headers=headers)
|
||||
|
||||
if response.status_code == 200:
|
||||
order_details = response.json()
|
||||
if order_details.get('result') == 'SUCCESS':
|
||||
OrderStatus.objects.create(
|
||||
order = order,
|
||||
status = 'Completed',
|
||||
date = datetime.now()
|
||||
)
|
||||
order_items = OrderItem.objects.filter(order=order)
|
||||
for order_item in order_items:
|
||||
order_item.purchased_at = datetime.now()
|
||||
if order_item.item.item_type.name == 'OSIMENU':
|
||||
api_url = 'https://osimenu.com/api/create-subscription/'
|
||||
random_string = ''.join(random.choices(string.ascii_letters + string.digits, k=10))
|
||||
end_date_str = order_item.end_at.strftime('%Y-%m-%d')
|
||||
api_data = {
|
||||
'user': {
|
||||
'username': request.user.email,
|
||||
'email': request.user.email,
|
||||
'password': random_string,
|
||||
'first_name': request.user.first_name,
|
||||
'last_name': request.user.last_name
|
||||
},
|
||||
'customer': {
|
||||
'mobile_number': request.user.customerprofile.mobile_number
|
||||
},
|
||||
'subscription': {
|
||||
'plan': order_item.item.title,
|
||||
'end_date': end_date_str
|
||||
}
|
||||
}
|
||||
response = requests.post(api_url, json=api_data)
|
||||
order_item.active = True
|
||||
old_order_items = OrderItem.objects.exclude(order__id=order.id).filter(item__item_type__name='OSIMENU', order__customer=request.user.customerprofile)
|
||||
for item in old_order_items:
|
||||
item.active = False
|
||||
item.save()
|
||||
order_item.save()
|
||||
add_invoice_pdf(request, order_id=order.id)
|
||||
return redirect('customerorders')
|
||||
error_message = 'Failed to retrieve order details: ' + response.text
|
||||
return JsonResponse({'error': error_message}, status=500)
|
||||
except Exception as e:
|
||||
error_message = 'Exception: ' + str(e)
|
||||
return JsonResponse({'error': error_message}, status=500)
|
||||
|
||||
|
||||
|
||||
|
||||
def buy_free_osimenu(request):
|
||||
api_url = 'https://osimenu.com/api/create-subscription/'
|
||||
random_string = ''.join(random.choices(string.ascii_letters + string.digits, k=10))
|
||||
api_data = {
|
||||
'user': {
|
||||
'username': request.user.email,
|
||||
'email': request.user.email,
|
||||
'password': random_string,
|
||||
'first_name': request.user.first_name,
|
||||
'last_name': request.user.last_name
|
||||
},
|
||||
'customer': {
|
||||
'mobile_number': request.user.customerprofile.mobile_number
|
||||
},
|
||||
'subscription': {
|
||||
'plan': 'OSIMENU BASIC'
|
||||
}
|
||||
}
|
||||
|
||||
order = Order.objects.create(
|
||||
customer = request.user.customerprofile,
|
||||
)
|
||||
|
||||
order_status = OrderStatus.objects.create(
|
||||
order=order,
|
||||
status = 'Completed',
|
||||
date = datetime.now()
|
||||
)
|
||||
|
||||
order_item = OrderItem.objects.create(
|
||||
order = order,
|
||||
item = get_object_or_404(Item, title='OSIMENU BASIC'),
|
||||
purchased_at = datetime.now(),
|
||||
active = True,
|
||||
)
|
||||
|
||||
old_order_items = OrderItem.objects.exclude(order__id=order.id).filter(item__item_type__name='OSIMENU', order__customer=request.user.customerprofile)
|
||||
for item in old_order_items:
|
||||
item.active = False
|
||||
item.save()
|
||||
|
||||
response = requests.post(api_url, json=api_data)
|
||||
print(response)
|
||||
return redirect('customerorders')
|
||||
|
||||
|
||||
|
||||
|
||||
def buy_free_osicard(request):
|
||||
api_url = 'https://mybusinesscardpage.com/api/create-subscription/'
|
||||
random_string = ''.join(random.choices(string.ascii_letters + string.digits, k=10))
|
||||
api_data = {
|
||||
'user': {
|
||||
'username': request.user.email,
|
||||
'email': request.user.email,
|
||||
'password': random_string,
|
||||
'first_name': request.user.first_name,
|
||||
'last_name': request.user.last_name
|
||||
},
|
||||
'customer': {
|
||||
'mobile_number': request.user.customerprofile.mobile_number
|
||||
},
|
||||
'subscription': {
|
||||
'plan': 'OSICARD BASIC'
|
||||
}
|
||||
}
|
||||
|
||||
order = Order.objects.create(
|
||||
customer = request.user.customerprofile,
|
||||
)
|
||||
|
||||
order_status = OrderStatus.objects.create(
|
||||
order=order,
|
||||
status = 'Completed',
|
||||
date = datetime.now()
|
||||
)
|
||||
|
||||
order_item = OrderItem.objects.create(
|
||||
order = order,
|
||||
item = get_object_or_404(Item, title='OSICARD BASIC'),
|
||||
purchased_at = datetime.now(),
|
||||
active = True,
|
||||
)
|
||||
|
||||
old_order_items = OrderItem.objects.exclude(order__id=order.id).filter(item__item_type__name='OSICARD', order__customer=request.user.customerprofile)
|
||||
for item in old_order_items:
|
||||
item.active = False
|
||||
item.save()
|
||||
|
||||
response = requests.post(api_url, json=api_data)
|
||||
print(response)
|
||||
return redirect('customerorders')
|
||||
|
||||
|
@ -0,0 +1,151 @@
|
||||
{% extends "customer_main.html" %}
|
||||
{%load static%}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div class="w-full px-5 s:px-9 flex flex-col gap-3">
|
||||
<div class="w-full bg-white rounded-md h-fit shadow-md p-5">
|
||||
<div
|
||||
class="w-full bg-gray-50 px-3 py-3 border border-gray-100 shadow-md rounded-md flex flex-col md:flex-row justify-between items-center gap-3">
|
||||
<div class="text-center xll:text-left">
|
||||
<h1 class="text-secondosiblue text-xl">Order {{order.order_id}}</h1>
|
||||
<p class="text-gray-500"></p>
|
||||
|
||||
{% if order.orderstatus.set_all.last.status %}
|
||||
<p>
|
||||
<span
|
||||
class="uppercase text-green-700 font-semibold text-sm {% if order.orderstatus.set_all.last.status == 'Completed' %} text-green-700 {% elif order.orderstatus.set_all.last.status == 'Pending' %} text-yellow-500 {% elif order.orderstatus.set_all.last.status == 'Failed' %} text-red-500 {% endif %}">{{order.status}}</span>
|
||||
<span class="text-sm font-light text-gray-500"> {{order.orderstatus.set_all.last.status}} -
|
||||
{{order.orderstatus.set_all.last.date}}</span>
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<p class="text-secondosiblue font-poppinsBold">Remaining Balance: $<span>12.00</span></p>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="w-full bg-gray-50 px-3 py-3 border border-gray-100 shadow-md rounded-md flex flex-col md:flex-row justify-end items-center gap-2 mt-3">
|
||||
{% if order.invoice %}
|
||||
<a class="w-full md:w-fit">
|
||||
<button
|
||||
class="w-full md:w-fit text-base px-3 py-2 bg-osiblue text-white outline-none border border-osiblue rounded-md cursor-pointer hover:bg-white hover:text-osiblue duration-300">
|
||||
Download Invoice
|
||||
</button>
|
||||
</a>
|
||||
{% endif %}
|
||||
|
||||
<a class="w-full md:w-fit">
|
||||
<button
|
||||
class="w-full md:w-fit text-base px-3 py-2 bg-osiblue text-white outline-none border border-osiblue rounded-md cursor-pointer hover:bg-white hover:text-osiblue duration-300">
|
||||
Download Statement
|
||||
</button>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
|
||||
{% if order_items %}
|
||||
<div class="w-full mt-10">
|
||||
<p class="text-secondosiblue text-xl">Order Items</p>
|
||||
<div class="w-full grid grid-cols-1 md:grid-cols-2 l:grid-cols-3 gap-5 mt-3">
|
||||
|
||||
{% for item in order_items %}
|
||||
<div class="w-full shadow-md border border-gray-200 flex flex-col justify-between rounded-md">
|
||||
<div
|
||||
class="w-full h-full p-9 flex flex-col justify-center items-center gap-5 rounded-t-md bg-white">
|
||||
<p class="text-secondosiblue uppercase font-poppinsBold text-xl text-center">{{item.item.title}}
|
||||
</p>
|
||||
</div>
|
||||
<div class="w-full flex flex-col justify-center items-center text-center mb-2">
|
||||
<p class="text-secondosiblue font-poppinsLight text-[17px] font-semibold">${{item.item.amount}}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
|
||||
<div class="overflow-x-auto border border-gray-300 rounded-t-md mt-10">
|
||||
<table class="min-w-full divide-y">
|
||||
<!-- TABLE HEADER -->
|
||||
<thead class="bg-gray-50">
|
||||
<tr>
|
||||
<th scope="col"
|
||||
class="px-6 py-3 text-sm font-medium text-gray-500 uppercase border-r border-gray-300 whitespace-nowrap">
|
||||
Amount
|
||||
</th>
|
||||
<th scope="col"
|
||||
class="px-6 py-3 text-sm font-medium text-gray-500 uppercase border-r border-gray-300 whitespace-nowrap ">
|
||||
Date Due
|
||||
</th>
|
||||
<th scope="col"
|
||||
class="px-6 py-3 text-sm font-medium text-gray-500 uppercase border-r border-gray-300 whitespace-nowrap">
|
||||
Date Paid
|
||||
</th>
|
||||
<th scope="col"
|
||||
class="px-6 py-3 text-sm font-medium text-gray-500 uppercase border-r border-gray-300 whitespace-nowrap">
|
||||
Comment
|
||||
</th>
|
||||
<th scope="col" class="px-6 py-3 text-sm font-medium text-gray-500 uppercase whitespace-nowrap">
|
||||
Payment
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<!-- TABLE BODY -->
|
||||
<tbody class="bg-white divide-y divide-gray-200">
|
||||
{% for payment in payments %}
|
||||
<tr>
|
||||
<td class="px-6 py-4 text-center text-sm border-r border-gray-300">
|
||||
<p class="text-secondosiblue">${{payment.amount}}</p>
|
||||
</td>
|
||||
|
||||
<td class="px-6 py-4 text-center text-sm border-r border-gray-300">
|
||||
{% if payment.date_due %}
|
||||
<p class="text-secondosiblue">{{payment.date_due}}</p>
|
||||
{% else %}
|
||||
<p class="text-secondosiblue">-</p>
|
||||
{% endif %}
|
||||
</td>
|
||||
|
||||
<td class="px-6 py-4 text-center text-sm border-r border-gray-300">
|
||||
{% if payment.date_paid %}
|
||||
<p class="text-secondosiblue">{{payment.date_paid}}</p>
|
||||
{% else %}
|
||||
<p class="text-red-500">UNPAID</p>
|
||||
{% endif %}
|
||||
</td>
|
||||
|
||||
<td class="px-6 py-4 text-center text-sm border-r border-gray-300">
|
||||
<p class="text-secondosiblue">Comment</p>
|
||||
</td>
|
||||
|
||||
<td class="px-6 py-4 text-center text-sm">
|
||||
<div class="flex flex-col justify-center items-center gap-3">
|
||||
{% for type in payment.type.all %}
|
||||
<a
|
||||
{% if type.name == 'Whish Money' %} href="{% url 'whishpayment' payment.id %}" {% endif %}
|
||||
{% if type.name == 'Credit & Debit Card' %} href="{% url 'cardpayment' payment.id %}" {% endif %}
|
||||
{% if type.name == 'Cash' %} href="{% url 'cashpayment' payment.id %}" {% endif %}>
|
||||
<div
|
||||
class="flex items-center gap-2 justify-center cursor-pointer text-secondosiblue hover:text-gray-400 duration-300">
|
||||
<img src="{{type.image.url}}" class="w-[30px] rounded-md shadow-sm">
|
||||
<p class="underline">{{type.name}}</p>
|
||||
</div>
|
||||
</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
@ -0,0 +1,274 @@
|
||||
{% extends "customer_main.html" %}
|
||||
{%load static%}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div class="w-full px-5 s:px-9 flex flex-col gap-3">
|
||||
<div class="w-full bg-white rounded-md h-fit shadow-md p-5">
|
||||
<div class="w-full bg-orange-500 rounded-md flex flex-col justify-center items-center py-2 gap-2 mt-[50px]">
|
||||
<div
|
||||
class="w-[70px] s:w-[90px] h-[70px] s:h-[90px] rounded-full mt-[-50px] s:mt-[-63px] border border-gray-300 bg-white">
|
||||
<img src="{% static 'images/ositcom_logos/full-logo.png' %}" alt="" class="w-full h-full object-cover rounded-full">
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<p class="text-xl text-white font-semibold">Winabig</p>
|
||||
<p class="text-sm text-white font-light">P20302</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="w-full flex flex-col gap-2 mt-3">
|
||||
<div class="w-full rounded-md bg-white shadow-md h-[8px]">
|
||||
<div class="w-[80%] h-full bg-green-700 rounded-md">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="w-full flex justify-between items-center gap-3 text-gray-500 font-light text-sm">
|
||||
<p>20-2-2023</p>
|
||||
<p>20-2-2024</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="w-full h-fit flex justify-end items-center bg-gray-100 shadow-md rounded-md px-3 py-3 mt-3">
|
||||
<div class="w-full s:w-fit flex flex-col s:flex-row justify-end items-center gap-3">
|
||||
<a href="" class="w-full s:w-fit">
|
||||
<button
|
||||
class="w-full s:w-fit text-base px-3 py-2 bg-osiblue text-white outline-none border border-osiblue rounded-md cursor-pointer hover:bg-white hover:text-osiblue duration-300">Add
|
||||
Ticket</button>
|
||||
</a>
|
||||
<a href="" class="w-full s:w-fit">
|
||||
<button
|
||||
class="w-full s:w-fit text-base px-3 py-2 bg-osiblue text-white outline-none border border-osiblue rounded-md cursor-pointer hover:bg-white hover:text-osiblue duration-300">Add
|
||||
User Story</button>
|
||||
</a>
|
||||
<a href="" class="w-full s:w-fit">
|
||||
<button
|
||||
class="w-full s:w-fit text-base px-3 py-2 bg-osiblue text-white outline-none border border-osiblue rounded-md cursor-pointer hover:bg-white hover:text-osiblue duration-300">Add
|
||||
Credentials</button>
|
||||
</a>
|
||||
<a href="" class="w-full s:w-fit">
|
||||
<button
|
||||
class="w-full s:w-fit text-base px-3 py-2 bg-osiblue text-white outline-none border border-osiblue rounded-md cursor-pointer hover:bg-white hover:text-osiblue duration-300">Add
|
||||
File</button>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="w-full bg-gray-50 rounded-md shadow-md border border-gray-100 p-5 mt-10">
|
||||
<p class="text-secondosiblue text-[17px] font-poppinsBold">Project Manager</p>
|
||||
<div
|
||||
class="w-[240px] px-5 py-2 bg-white shadow-md mt-3 rounded-md flex justify-start items-center gap-2 cursor-pointer">
|
||||
<div class="w-[50px] h-[50px] rounded-full">
|
||||
<img src="{% static 'images/default-user.png' %}"
|
||||
class="w-full h-full object-cover shadow-md rounded-full">
|
||||
</div>
|
||||
<p class="text-gray-500 text-[16px]">Emile Elliye</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div class="w-full bg-gray-50 rounded-md shadow-md border border-gray-100 p-5 mt-10">
|
||||
<p class="text-secondosiblue text-[17px] font-poppinsBold">Project Details</p>
|
||||
<p class="text-gray-500 font-light leading-7">There are many variations of passages of Lorem Ipsum
|
||||
available, but the majority have suffered alteration
|
||||
in some form, by injected humour, or randomised words which don't look even slightly believable. If you
|
||||
are going to use a passage of Lorem Ipsum, you need to be sure there isn't anything embarrassing hidden
|
||||
in the middle of text. All the Lorem Ipsum generators on the Internet tend to repeat predefined chunks
|
||||
as necessary, making this the first true generator on the Internet. It uses a dictionary of over 200
|
||||
Latin words, combined with a handful of model sentence structures, to generate Lorem Ipsum which looks
|
||||
reasonable. The generated Lorem Ipsum is therefore always free from repetition, injected humour, or
|
||||
non-characteristic words etc.</p>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- USER STORIES -->
|
||||
<div class="w-full mt-10">
|
||||
<div class="overflow-x-auto border border-gray-300 rounded-md mt-5">
|
||||
<div
|
||||
class=" bg-gray-200 rounded-t-md flex justify-between items-center text-white text-xl font-bold h-[50px]">
|
||||
<div class="px-3">
|
||||
<p class="text-secondosiblue uppercase font-bold">User Stories</p>
|
||||
</div>
|
||||
|
||||
<button
|
||||
class="h-full rounded-tr-md px-4 bg-secondosiblue text-gray-200 text-[18px] outline-none border-none cursor-pointer flex justify-center items-center addUserStoryButton"
|
||||
data-modal-url="">
|
||||
<i class="fa fa-plus"></i>
|
||||
</button>
|
||||
</div>
|
||||
<table class="min-w-full divide-y">
|
||||
<!-- TABLE HEADER -->
|
||||
<thead class="bg-gray-50">
|
||||
<tr>
|
||||
<th scope="col"
|
||||
class="px-6 py-3 text-sm font-medium text-gray-500 uppercase border-r border-gray-300 whitespace-nowrap">
|
||||
Story
|
||||
</th>
|
||||
<th scope="col"
|
||||
class="px-6 py-3 text-sm font-medium text-gray-500 uppercase border-r border-gray-300 whitespace-nowrap">
|
||||
Related Task
|
||||
</th>
|
||||
<th scope="col"
|
||||
class="px-6 py-3 text-sm font-medium text-gray-500 uppercase whitespace-nowrap">
|
||||
Actions
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<!-- TABLE BODY -->
|
||||
<tbody class="bg-white divide-y divide-gray-200">
|
||||
<tr>
|
||||
<td class="px-6 py-4 text-center text-sm border-r border-gray-300">
|
||||
<p class="text-secondosiblue">requirements</p>
|
||||
</td>
|
||||
|
||||
<td class="px-6 py-4 text-center text-sm border-r border-gray-300">
|
||||
dddd
|
||||
</td>
|
||||
|
||||
|
||||
<td class="px-6 py-4 text-center text-sm">
|
||||
<div class="w-full flex justify-center items-center gap-3">
|
||||
<a href="">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
|
||||
stroke-width="1.5" stroke="currentColor"
|
||||
class="w-[18px] text-fifthosiblue hover:scale-110 duration-500 transition-transform">
|
||||
<path stroke-linecap="round" stroke-linejoin="round"
|
||||
d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L10.582 16.07a4.5 4.5 0 0 1-1.897 1.13L6 18l.8-2.685a4.5 4.5 0 0 1 1.13-1.897l8.932-8.931Zm0 0L19.5 7.125M18 14v4.75A2.25 2.25 0 0 1 15.75 21H5.25A2.25 2.25 0 0 1 3 18.75V8.25A2.25 2.25 0 0 1 5.25 6H10" />
|
||||
</svg>
|
||||
</a>
|
||||
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
|
||||
stroke-width="1.5" stroke="currentColor"
|
||||
class="w-[18px] text-red-500 hover:scale-110 duration-500 transition-transform">
|
||||
<path stroke-linecap="round" stroke-linejoin="round"
|
||||
d="m14.74 9-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 0 1-2.244 2.077H8.084a2.25 2.25 0 0 1-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 0 0-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 0 1 3.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 0 0-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 0 0-7.5 0" />
|
||||
</svg>
|
||||
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- CREDENTIALS -->
|
||||
<div class="mt-10 relative">
|
||||
<div
|
||||
class=" bg-gray-200 rounded-t-md flex justify-between items-center text-white text-xl font-bold h-[50px]">
|
||||
<div class="px-3">
|
||||
<p class="text-secondosiblue uppercase font-bold">Credentials</p>
|
||||
</div>
|
||||
|
||||
<button
|
||||
class="h-full rounded-tr-md px-4 bg-secondosiblue text-gray-200 text-[18px] outline-none border-none cursor-pointer flex justify-center items-center addCredentialsButton"
|
||||
data-modal-url="">
|
||||
<i class="fa fa-plus"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="overflow-x-auto border border-gray-300 rounded-b-md">
|
||||
<table class="min-w-full divide-y">
|
||||
<!-- TABLE HEADER -->
|
||||
<thead class="bg-gray-50">
|
||||
<tr>
|
||||
<th scope="col"
|
||||
class="px-6 py-3 text-sm font-medium text-gray-500 uppercase border-r border-gray-300 whitespace-nowrap">
|
||||
Email or Username
|
||||
</th>
|
||||
<th scope="col"
|
||||
class="px-6 py-3 text-sm font-medium text-gray-500 uppercase border-r border-gray-300 whitespace-nowrap">
|
||||
Password
|
||||
</th>
|
||||
<th scope="col"
|
||||
class="px-6 py-3 text-sm font-medium text-gray-500 uppercase whitespace-nowrap">
|
||||
Used For
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<!-- TABLE BODY -->
|
||||
<tbody class="bg-white divide-y divide-gray-200">
|
||||
<!-- 1st row -->
|
||||
<tr>
|
||||
<td class="px-6 py-4 text-center text-sm border-r border-gray-300">
|
||||
<p class="text-secondosiblue">{{credential.emailorusername}}</p>
|
||||
</td>
|
||||
|
||||
<td class="px-6 py-4 text-center text-sm border-r border-gray-300">
|
||||
<a class="text-secondosiblue">{{credential.password}}</a>
|
||||
</td>
|
||||
|
||||
<td class="px-6 py-4 text-center text-sm">
|
||||
<a class="text-secondosiblue">{{credential.usedfor}}</a>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- RELATED FILES -->
|
||||
<div class="w-full mt-10">
|
||||
<div class="overflow-x-auto border border-gray-300 rounded-md mt-5">
|
||||
<div
|
||||
class=" bg-gray-200 rounded-t-md flex justify-between items-center text-white text-xl font-bold h-[50px]">
|
||||
<div class="px-3">
|
||||
<p class="text-secondosiblue uppercase font-bold">Related files</p>
|
||||
</div>
|
||||
|
||||
<button
|
||||
class="h-full rounded-tr-md px-4 bg-secondosiblue text-gray-200 text-[18px] outline-none border-none cursor-pointer flex justify-center items-center addFileButton"
|
||||
data-modal-url="">
|
||||
<i class="fa fa-plus"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<table class="min-w-full divide-y">
|
||||
<!-- TABLE HEADER -->
|
||||
<thead class="bg-gray-50">
|
||||
<tr>
|
||||
<th scope="col"
|
||||
class="px-6 py-3 text-sm font-medium text-gray-500 uppercase border-r border-gray-300 whitespace-nowrap">
|
||||
File Name
|
||||
</th>
|
||||
<th scope="col"
|
||||
class="px-6 py-3 text-sm font-medium text-gray-500 uppercase border-r border-gray-300 whitespace-nowrap">
|
||||
File
|
||||
</th>
|
||||
<th scope="col"
|
||||
class="px-6 py-3 text-sm font-medium text-gray-500 uppercase whitespace-nowrap">
|
||||
Date Entered
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<!-- TABLE BODY -->
|
||||
<tbody class="bg-white divide-y divide-gray-200">
|
||||
<!-- 1st row -->
|
||||
<tr>
|
||||
<td class="px-6 py-4 text-center text-sm border-r border-gray-300">
|
||||
<p class="text-secondosiblue">{{file.name}}</p>
|
||||
</td>
|
||||
|
||||
<td class="px-6 py-4 text-center text-sm border-r border-gray-300">
|
||||
<a class="text-secondosiblue">{{file.file}}</a>
|
||||
</td>
|
||||
|
||||
<td class="px-6 py-4 text-center text-sm">
|
||||
<a class="text-secondosiblue">{{file.date}}</a>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock content %}
|
@ -0,0 +1,89 @@
|
||||
{% extends "customer_main.html" %}
|
||||
{%load static%}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div class="w-full px-5 s:px-9 flex flex-col gap-3">
|
||||
<div class="w-full bg-white rounded-md h-fit shadow-md p-5">
|
||||
<h1 class="text-secondosiblue text-[25px]">My Projects</h1>
|
||||
|
||||
<div class="w-full grid grid-cols-1 l:grid-cols-2 gap-5 mt-4">
|
||||
<a href="{% url 'customerprojectdetails' %}">
|
||||
<div
|
||||
class="w-full rounded-md flex flex-col justify-between items-center gap-3 px-5 py-9 h-[250px] bg-gray-50 shadow-md relative hover:bg-gray-100 duration-300">
|
||||
<div class="flex flex-col justify-center items-center gap-5">
|
||||
<div
|
||||
class="w-[70px] h-[70px] rounded-full shadow-md">
|
||||
<img src="{% static 'images/ositcom_logos/full-logo.png' %}" class="w-full h-full rounded-full object-cover">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<p class="text-secondosiblue font-poppinsBold text-center text-xl">Geologist Safwat</p>
|
||||
<p class="text-sm uppercase font-light text-secondosiblue text-center">P240022</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="bg-orange-500 px-3 py-2 rounded-r-md text-xs text-white font-light uppercase absolute top-5 left-0">
|
||||
<p>Active</p>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="w-full mt-5 flex flex-col gap-2">
|
||||
<div class="w-full flex justify-between items-center gap-3 text-gray-500 font-light text-xs">
|
||||
<p>20-2-2023</p>
|
||||
<p>20-2-2024</p>
|
||||
</div>
|
||||
<div class="w-full rounded-md bg-white shadow-md h-[8px]">
|
||||
<div class="w-[80%] h-full bg-green-700 rounded-md">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</a>
|
||||
|
||||
|
||||
<a href="{% url 'customerprojectdetails' %}">
|
||||
<div
|
||||
class="w-full rounded-md flex flex-col justify-between items-center gap-3 px-5 py-9 h-[250px] bg-gray-50 shadow-md relative hover:bg-gray-100 duration-300">
|
||||
<div class="flex flex-col justify-center items-center gap-5">
|
||||
<div
|
||||
class="w-[70px] h-[70px] rounded-full shadow-md">
|
||||
<img src="{% static 'images/ositcom_logos/full-logo.png' %}" class="w-full h-full rounded-full object-cover">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<p class="text-secondosiblue font-poppinsBold text-center text-xl">Geologist Safwat</p>
|
||||
<p class="text-sm uppercase font-light text-secondosiblue text-center">P240022</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="bg-yellow-500 px-3 py-2 rounded-r-md text-xs text-white font-light uppercase absolute top-5 left-0">
|
||||
<p>Pending</p>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="w-full mt-5 flex flex-col gap-2">
|
||||
<div class="w-full flex justify-between items-center gap-3 text-gray-500 font-light text-xs">
|
||||
<p>May,2,2023</p>
|
||||
<p>June,30,2023</p>
|
||||
</div>
|
||||
<div class="w-full rounded-md bg-white shadow-md h-[8px]">
|
||||
<div class="w-[90%] h-full bg-red-500 rounded-md">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</a>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{% endblock content %}
|
@ -0,0 +1,78 @@
|
||||
{% extends "customer_main.html" %}
|
||||
{%load static%}
|
||||
|
||||
{% block modules_section %}
|
||||
<!-- This block is intentionally left empty to exclude the modules section -->
|
||||
{% endblock modules_section %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
|
||||
|
||||
<div class="w-full px-5 s:px-9 flex flex-col gap-5 mt-5 font-poppinsLight">
|
||||
<div class="w-full h-fit bg-white rounded-md shadow-md">
|
||||
<div class="grid grid-cols-1 xxlg1:grid-cols-2">
|
||||
<div
|
||||
class="w-full pb-9 flex flex-col items-center justify-between rounded-lb-none xxlg1:rounded-l-md h-full rounded-tl-md rounded-tr-md xxlg1:rounded-tr-none gap-10 overflow-hidden relative bg-gradient-to-b from-gray-400 via-gray-500 to-blue-950">
|
||||
<div
|
||||
class="absolute top-0 left-32 w-[400px] h-[400px] bg-slate-800 filter blur-xl opacity-70 animate-blob animation-delay-2000">
|
||||
</div>
|
||||
<div
|
||||
class="absolute top-20 right-0 w-[400px] h-[400px] bg-osiblue filter blur-xl opacity-70 animate-blob animation-delay-2000">
|
||||
</div>
|
||||
<div
|
||||
class="absolute bottom-0 left-10 w-[400px] h-[400px] bg-blue-900 filter blur-xl opacity-70 animate-blob animation-delay-2000">
|
||||
</div>
|
||||
<div
|
||||
class="absolute bottom-0 right-36 w-[400px] h-[400px] bg-gray-400 filter blur-xl opacity-70 animate-blob animation-delay-2000">
|
||||
</div>
|
||||
|
||||
<div></div>
|
||||
|
||||
<!-- INVOICE DETAILS -->
|
||||
<div class="w-[90%] s:w-[85%] xll:w-[75%] h-fit flex flex-col gap-5 justify-center items-center py-9 bg-white rounded-md z-10 shadow-md duration-300">
|
||||
<img src="{% static 'images/ositcom_logos/full-logo.png' %}" class="w-[120px]">
|
||||
|
||||
<div class="w-full bg-osiblue py-3 px-3 flex justify-between items-center text-white mt-5">
|
||||
<p>Due Date: <span class="font-semibold">{{payment.date_due}}</span></p>
|
||||
</div>
|
||||
|
||||
<div class="w-full p-5">
|
||||
<p class="font-poppinsBold text-secondosiblue text-[17px]">Bill To:</p>
|
||||
<p class="text-secondosiblue font-light">{{payment.order.customer.user.first_name}} {{payment.order.customer.user.last_name}}</p>
|
||||
<p class="text-secondosiblue font-light">{{payment.order.customer.mobile_number}}</p>
|
||||
<p class="text-secondosiblue font-light">{{payment.order.customer.user.email}}</p>
|
||||
</div>
|
||||
|
||||
<div class="w-full bg-osiblue py-3 px-3 flex justify-start items-center text-white">
|
||||
<p>Invoice Items</p>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="w-full flex flex-col gap-5 p-5">
|
||||
<ul class="text-secondosiblue font-light list-disc px-5">
|
||||
{% for item in payment.order.orderitem_set.all %}
|
||||
<li>{{item.item.title}}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
<div class="w-full flex justify-end items-center text-secondosiblue text-xl">
|
||||
<p>Total: <span class="font-semibold">${{payment.order.get_cart_total}}</span></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<!-- CASH PAYMENT CONTAINER -->
|
||||
<div class="w-full flex flex-col justify-between items-center gap-5">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
{% endblock %}
|
@ -0,0 +1,88 @@
|
||||
{% extends "customer_main.html" %}
|
||||
{%load static%}
|
||||
|
||||
{% block modules_section %}
|
||||
<!-- This block is intentionally left empty to exclude the modules section -->
|
||||
{% endblock modules_section %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
|
||||
|
||||
<div class="w-full px-5 s:px-9 flex flex-col gap-5 mt-5 font-poppinsLight">
|
||||
<div class="w-full h-fit bg-white rounded-md shadow-md">
|
||||
<div class="grid grid-cols-1 xxlg1:grid-cols-2">
|
||||
<div
|
||||
class="w-full pb-9 flex flex-col items-center justify-between rounded-lb-none xxlg1:rounded-l-md h-full rounded-tl-md rounded-tr-md xxlg1:rounded-tr-none gap-10 overflow-hidden relative bg-gradient-to-b from-gray-400 via-gray-500 to-blue-950">
|
||||
<div
|
||||
class="absolute top-0 left-32 w-[400px] h-[400px] bg-slate-800 filter blur-xl opacity-70 animate-blob animation-delay-2000">
|
||||
</div>
|
||||
<div
|
||||
class="absolute top-20 right-0 w-[400px] h-[400px] bg-osiblue filter blur-xl opacity-70 animate-blob animation-delay-2000">
|
||||
</div>
|
||||
<div
|
||||
class="absolute bottom-0 left-10 w-[400px] h-[400px] bg-blue-900 filter blur-xl opacity-70 animate-blob animation-delay-2000">
|
||||
</div>
|
||||
<div
|
||||
class="absolute bottom-0 right-36 w-[400px] h-[400px] bg-gray-400 filter blur-xl opacity-70 animate-blob animation-delay-2000">
|
||||
</div>
|
||||
|
||||
<div></div>
|
||||
|
||||
<!-- INVOICE DETAILS -->
|
||||
<div class="w-[90%] s:w-[85%] xll:w-[75%] h-fit flex flex-col gap-5 justify-center items-center py-9 bg-white rounded-md z-10 shadow-md duration-300">
|
||||
<img src="{% static 'images/ositcom_logos/full-logo.png' %}" class="w-[120px]">
|
||||
|
||||
<div class="w-full bg-osiblue py-3 px-3 flex justify-between items-center text-white mt-5">
|
||||
<p>Due Date: <span class="font-semibold">{{payment.date_due}}</span></p>
|
||||
</div>
|
||||
|
||||
<div class="w-full p-5">
|
||||
<p class="font-poppinsBold text-secondosiblue text-[17px]">Bill To:</p>
|
||||
<p class="text-secondosiblue font-light">{{payment.order.customer.user.first_name}} {{payment.order.customer.user.last_name}}</p>
|
||||
<p class="text-secondosiblue font-light">{{payment.order.customer.mobile_number}}</p>
|
||||
<p class="text-secondosiblue font-light">{{payment.order.customer.user.email}}</p>
|
||||
</div>
|
||||
|
||||
<div class="w-full bg-osiblue py-3 px-3 flex justify-start items-center text-white">
|
||||
<p>Invoice Items</p>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="w-full flex flex-col gap-5 p-5">
|
||||
<ul class="text-secondosiblue font-light list-disc px-5">
|
||||
{% for item in payment.order.orderitem_set.all %}
|
||||
<li>{{item.item.title}}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
<div class="w-full flex justify-end items-center text-secondosiblue text-xl">
|
||||
<p>Total: <span class="font-semibold">${{payment.order.get_cart_total}}</span></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<!-- WHISH CONTAINER -->
|
||||
<div class="w-full flex flex-col justify-between items-center gap-5">
|
||||
<div class="w-full flex flex-col justify-center items-center gap-8 p-9">
|
||||
<p class="text-center text-secondosiblue font-poppinsBold text-xl s:text-2xl">Scan this QR on Your Whish Mobile Application<br> to Proceed Payment</p>
|
||||
<img src="{% static 'images/whish-qr.jpeg' %}" class="w-[300px]">
|
||||
</div>
|
||||
|
||||
|
||||
<div class="w-full flex justify-center items-center gap-2 border-t border-gray-100 pt-5 py-5 px-9">
|
||||
<img src="{% static 'images/whishlogo.png' %}" class="w-[35px] rounded-md">
|
||||
<p class="text-secondosiblue text-sm font-light">Payment By Whish Money</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
{% endblock %}
|
After Width: | Height: | Size: 20 KiB |
After Width: | Height: | Size: 303 KiB |
After Width: | Height: | Size: 18 KiB |
After Width: | Height: | Size: 303 KiB |
After Width: | Height: | Size: 45 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 15 KiB |