收藏网站

Django 超市收银软件

2020年12月4日 13:18 Django 5413

Python Django制作一个简单的超市收银系统,基本设计思路是:收银系统打开的时候条码框自动获得焦点,用条码枪输入提前录入好的商品,并在页面显示商品信息,如果多次扫描同一条码,数量和金额会增加。"收款金额"输入金额回车后获得找零金额,点击保存按钮,将此次的收款数据存入数据库。"取消"按钮会清空当前收银数据,刷新页面、刷新流水单号。

Django收银软件

设计环境

# 超市收银软件设计环境

Python:3.9.0
Django:3.1.3
Mysql:8.0.22
Pycharm:2020.2


创建项目后新建一个应用sale(收银功能)

数据模型

# 收银数据表 models.py

from django.db import models


class Category(models.Model):
    """商品分类"""
    category_name = models.CharField('分类',max_length=32)
    decription = models.CharField('描述',max_length=200)

    class Meta:
        verbose_name = '商品分类'
        verbose_name_plural = '分类'

    def __str__(self):
        return self.category_name


class Product(models.Model):
    """商品数据模型"""
    product_id = models.CharField('商品编码',max_length=128)
    barcode = models.CharField('条形码',max_length=128)
    product_name = models.CharField('商品名称',max_length=200)
    unit = models.CharField('单位',max_length=32)
    unit_price = models.DecimalField(verbose_name='单价',max_digits=8,decimal_places=2)
    category = models.ForeignKey(Category,verbose_name='分类',on_delete=models.CASCADE,default=1)
    inventory = models.CharField('库存',max_length=64)

    class Meta:
        verbose_name = '商品'
        verbose_name_plural = '商品'

    def __str__(self):
        return self.product_name


class SaleList(models.Model):
    """收银数据模型"""
    order_code = models.CharField('订单编号',max_length=128)
    total_number = models.CharField('数量',max_length=32)
    total_price = models.CharField('总金额',max_length=128)
    receive_money = models.DecimalField('收款金额',max_digits=8,decimal_places=2)
    return_money = models.DecimalField('找零金额',max_digits=8,decimal_places=2)

    class Meta:
        verbose_name = verbose_name_plural = '收银数据'

    def __str__(self):
        return self.order_code


class SaleDetail(models.Model):
    """收银详细数据"""
    detail_number = models.CharField('订单编号',max_length=128)
    product_id = models.CharField('商品编号',max_length=128)
    product_name = models.CharField('商品名称', max_length=200)
    unit = models.CharField('单位', max_length=32)
    unit_price = models.DecimalField(verbose_name='单价', max_digits=8, decimal_places=2)
    number = models.CharField('数量',max_length=32)
    money = models.DecimalField('合计',max_digits=8,decimal_places=2)

    class Meta:
        verbose_name = '收银明细'
        verbose_name_plural = '收银明细'

    def __str__(self):
        return self.detail_number

由于只是一个演示案例,并没有设计商品管理功能,录入商品有两种方式,数据库操作和Django自带的Admin后台。

业务代码

在sale目录下创建一个myclass文件夹,并新建sale_id.py(流水单号)、shop_sale.py(收银功能)两个模块,用来具体实现业务功能。

# 自动流水单号 sale_id.py

from datetime import datetime
import random


# 根据当前时间随机生成流水单号
class OrderCode:
    # 构造函数
    def __init__(self):
        self.serialnum = ''  # 存储生成的单号,默认为空
        # 自动执行函数
        self.get_serialnum()

    def get_serialnum(self):
        """生成订单号"""
        # 获取当前系统时间
        dt = datetime.now()
        # 生成订单号
        self.serialnum = '%04d%02d%02d%02d%02d%02d' % (dt.year,dt.month,dt.day,dt.hour,dt.minute,dt.second)
        # 生成4位随机数字
        ran_list = random.randint(0,9999)
        # 随机数附加到尾部
        self.serialnum += '%04d' % (ran_list)


if __name__ == '__main__':
    obj = OrderCode()
    print(obj.serialnum)
# 收银功能的具体代码 shop_sale.py

from sale.models import Product,SaleList,SaleDetail
from decimal import Decimal


class Customer:
    # 构造函数
    def __init__(self):
        self.buy_list = []  # 储存当前扫描的商品
        self.total_number = 0  # 储存收银商品总数
        self.total_money = 0.0  # 存储收银总金额
        self.receive_money = 0.0  # 存储收款金额
        self.return_money = 0.0  # 存储找零金额

    def get_product(self,barcode):
        """收银模块:通过条形码查找商品"""

        if barcode is not None:
            try:
                product = Product.objects.filter(barcode=barcode).first()
                # 添加商品到收银列表
                self.add_product_buylist(product)
            except Exception as e:
                self.error_info = "商品扫描失败:" + str(e)

    def add_product_buylist(self,product):
        """收银模块:添加商品到收银列表"""
        temp_list = {
            'product_id':product.product_id,
            'product_barcode':product.barcode,
            'product_name':product.product_name,
            'unit':product.unit,
            'unit_price':product.unit_price,
            'money':product.unit_price,
            'number':1,
        }

        # 添加到当前的buy_list
        if len(self.buy_list) == 0:
            self.buy_list.append(temp_list)
        else:
            # 遍历当前的buy_list
            for index in range(len(self.buy_list)):
                if temp_list['product_id'] == self.buy_list[index]['product_id']:
                    self.buy_list[index]['number'] +=1
                    self.buy_list[index]['money'] = self.buy_list[index]['unit_price'] * self.buy_list[index]['number']
                    break
                if index == len(self.buy_list) -1:
                    self.buy_list.append(temp_list)

    def get_total_info(self):
        """收银模块:商品总数和总金额"""
        self.total_number = 0
        self.total_money = Decimal(0.0)

        # 遍历收银的商品列表
        for product in self.buy_list:
            self.total_number +=product['number']
            self.total_money +=product['money']
        # 保留金额的两位小数
        self.total_money = round(self.total_money,2)

    def get_receive_return_money(self, receive):
        """收银模块:收款金额和找零"""
        if receive is not None:
            self.receive_money = Decimal(receive)
            self.return_money = self.receive_money - self.total_money
        else:
            pass

    def delete_product_buylist(self,barcode):
        """收银模块:删除列表中的商品"""
        # 先遍历buy_list
        for index in range(len(self.buy_list)):
            # 判断传递过来的条形码是否在buy_list中,这里中括号中的product_barcode要和上面buy_list中的一样
            if int(self.buy_list[index]['product_barcode']) == int(barcode):
                self.buy_list.pop(index)
            else:
                continue

    def submit_sale_buylist(self,serialnum):
        """收银模块:保存到数据库"""
        # 保存每个收银单的总数据
        if self.buy_list is not None:
            try:
                sql_temp = SaleList.objects.create(order_code=serialnum,total_number=self.total_number,
                                                   total_price=self.total_money,receive_money=self.receive_money,
                                                   return_money=self.return_money)
            except Exception as e:
                self.error_info = '收银数据保存失败:' + str(e)
            # 遍历收银列表,把收银详细数据存储到SaleDetail表中
            for product in self.buy_list:
                try:
                    buy_sql = SaleDetail.objects.create(detail_number=serialnum,product_id=product['product_id'],
                                                        product_name=product['product_name'],unit=product['unit'],
                                                        unit_price=product['unit_price'],number=product['number'],
                                                        money=product['money'])
                except Exception as e:
                    self.error_info = '收银详细数据出错:' + str(e)
# views.py

from django.shortcuts import render,redirect
from sale.myclass import shop_sale,sale_id  # 引用自定义模块


# 实例化收银模块
sale_customer = shop_sale.Customer()
# 实例化自动单号
sale_time = sale_id.OrderCode()


def sale(request):
    """收银模块:显示"""
    if len(sale_time.serialnum) == 0:
        sale_time.serialnum()

    # 统计总数量和金额
    sale_customer.get_total_info()
    context = {
        'sale_id':sale_time.serialnum,
        'sale_customer':sale_customer,

    }
    return render(request,'sale/sale.html',context)


def add_sale(request):
    """收银模块:添加商品到收银列表"""
    # 获取当前的条形码
    barcode = request.GET.get('barcode')

    # 添加到buy_list
    sale_customer.get_product(barcode)

    return redirect('/sale/')


def get_return_money(request):
    """收银模块:收款金额和找零"""
    receive = request.GET.get('receive')
    if receive is not None:
        sale_customer.get_receive_return_money(receive)
    else:
        return redirect('/sale/')

    return redirect('/sale/')


def delete_product(request,barcode):
    """收银模块:删除商品"""
    sale_customer.delete_product_buylist(barcode)
    return redirect('/sale/')


def cancel_sale(request):
    """收银模块:取消订单"""
    sale_customer.buy_list.clear()  # 清空当前商品列表
    sale_id.serialnum = ''  # 清空当前单号
    sale_customer.total_number = 0  # 清空商品数量
    sale_customer.total_money = 0.0  # 清空总金额
    sale_customer.receive_money = 0.0  # 清空收款金额
    sale_customer.return_money = 0.0  # 清空找零金额

    return redirect('/sale/')


def submit_sale(request):
    """收银模块:提交到数据库"""
    sale_customer.submit_sale_buylist(sale_time.serialnum)
    sale_customer.buy_list.clear()  # 清空当前商品列表
    sale_id.serialnum = ''  # 清空当前单号
    sale_customer.total_number = 0  # 清空商品数量
    sale_customer.total_money = 0.0  # 清空总金额
    sale_customer.receive_money = 0.0  # 清空收款金额
    sale_customer.return_money = 0.0  # 清空找零金额
    return redirect('/sale/')

URL路由设置

# urls路由设置

from django.urls import path
from sale.views import sale,add_sale,get_return_money,delete_product,cancel_sale,submit_sale

urlpatterns = [
    path('',sale,name='sale'),  # 收银模块
    path('add_sale/',add_sale,name='add_sale'),  # 添加收银商品
    path('get_return/',get_return_money,name='get_return'),  # 计算收款金额
    path('del_sale/<int:barcode>',delete_product,name='del_sale'),  # 删除收银商品
    path('cancel_sale/',cancel_sale,name='cancel_sale'),  # 取消当前订单
    path('submit_sale/',submit_sale,name='submit_sale'),  # 保存订单
]

HTML模版文件

# 收银系统前端模版 sale.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>收银系统</title>
    <link type="text/css" rel="stylesheet" href="/images/css/common.css">
    <script src="/images/js/jquery.js"></script>
</head>

<body>
    <header>
        <div class="logo"><img src="/images/logo.png"></div>

    </header>
    <main>
        <table id="product_table">
            <thead>
                <tr>
                    <th>序号</th>
                    <th>商品编码</th>
                    <th>商品名称</th>
                    <th>单价</th>
                    <th>数量</th>
                    <th>单位</th>
                    <th>小计</th>
                    <th>操作</th>
                </tr>

            </thead>
            <tbody>
                {% for list in sale_customer.buy_list %}
                <tr>
                    <td>{{ forloop.counter }}</td>
                    <td>{{ list.product_barcode }}</td>
                    <td>{{ list.product_name }}</td>
                    <td>{{ list.unit_price }}</td>
                    <td>{{ list.number }}</td>
                    <td>{{ list.unit }}</td>
                    <td>{{ list.money }}</td>

                    <td><a href="{% url 'del_sale' list.product_barcode %}">删除</a></td>
                </tr>
                {% endfor %}
            </tbody>
        </table>

    </main>
    <footer>
        <div class="code_info">
            <span>操作人:<font>{{ request.session.nickname }}</font></span>
            <span>流水单号:<font>{{ sale_id }}</font></span>
        </div>
        <form>
            <p>
                <input type="text" id="barcode" name="barcode" placeholder="请扫描条形码" autofocus="autofocus" autocomplete="off">
                <input type="text" id="receive" name="receive" placeholder="收款金额" autocomplete="off">
            </p>
            <p>
                <span id="total_num">总数量:<font>{{ sale_customer.total_number }}</font></span>
                <span id="total_money">总金额:<font>{{ sale_customer.total_money }}</font></span>
                <span id="return">找零:<font>{{ sale_customer.return_money }}</font></span>
            </p>
            <div class="btn">
                <a href="{% url 'submit_sale' %}" class="save">保存</a>
                <a href="{% url 'cancel_sale' %}" class="cancel">取消</a>
            </div>
        </form>
    </footer>
    <script>
        $(function() {
            $('#barcode').bind('keydown', function(event) {
                var event = window.event || arguments.callee.caller.arguments[0];
                if (event.keyCode == 13) {
                    // 获取商品条形码
                    barcode = $("#barcode").val();
                    location.href = "{% url 'add_sale' %}?barcode=" + barcode;
                }
            });

            $('#receive').bind('keydown', function(event) {
                var event = window.event || arguments.callee.caller.arguments[0];
                if (event.keyCode == 13) {
                    // 获取商品条形码
                    receive = $("#receive").val();
                    if (receive == null || receive === '') {
                        location.href = "{% url 'sale' %}";
                    } else {
                        location.href = "{% url 'get_return' %}?receive=" + receive;
                    }
                }
            });
        });
    </script>
</body>

</html>

以上就是一个基本的收银软件,可以根据自己的需求对功能进行完善。结构很简单,知识点其实是将收银数据临时放到字典和列表中,当激活保存业务时,收银数据才会储存到数据库。

热点推荐

扫码添加微信