Multiple payments related to multiple customer implementation in django - django

I'm writing a customer management system for my business and got stuck on the payments entry system. This will run on a local dedicated server and should have only one user so code performance is not really an issue.
Every adult customer who enters the store is given a numbered card (Card, for the rest of this question) and his/her ID ( from Customer model ) is attached to it by a foreign key relation. There is an "entrance fee subtotal", which is the result of a choice field on Card model (there's only two choices and those won't change for a long time) plus kids 'fees'.
This, along with other two kind of models ( Product and Service), will compose the customer's bill. I have it working just fine, except on the payments registration.
As many Customers may be part of a family, and they may split their total bill quite often, I do believe Payment should be a model with an ManyToManyField related to Card so it could cover multiple payments methods ( treated as another choice field, since it will be either money, credit or debit cards ) but I can't figure it out how to model it neither how to handle it in my view/template.
I'm using django 1.9 & postgres 9.5 & python 2.7.
Bootstrap 3 along with some JS for styling (probably irrelevant).
Enough said, here's some code:
models.py
class Customer(models.Model):
id = models.AutoField(primary_key=True) #unnecessary but I had already written it
name = models.CharField(max_length=40)
last = models.CharField(max_length=80)
class Card(models.Model):
entrance_type1 = 1
entrance_type2 = 2
entrance_choices = (
(entrance_type1, 'Fun'),
(entrance_type2, 'Really Fun, kinda expensive'),
)
entrance_types = {
1:"Fun",
2:"Really Fun",
}
entrance_fee= {
'kid':5.0,
entrance_type1:15.0,
entrance_type1:35.0,
}
id = models.AutoField(primary_key=True) #Yeah, I do that
date = models.DateTimeField(auto_now=True, auto_now_add=False)
card_number = models.IntegerField()
entrance_type = models.PositiveIntegerField(choices=entrance_choices)
kids_number = models.PositiveIntegerField()
id_costumer = models.ForeignKey(Customer)
entrances_value = models.DecimalField(max_digits=6, decimal_places=2)
#will be entrance_fee[entrance_type] + entrance_fee['kid'] * kids_number
status = models.BooleanField(default=1) #should be 0 after payment(s)
Anyway, I really need help modelling payments for those. It should contain payment method, date and to which Cards it's related to.
I'm already getting ideas on the views/template step so I won't be strict about those on answers.
I do believe my question is kinda fuzzy and confuse, but can't figure how to make it better ( and maybe this is why I can't solve it by myself ) so please comment in your doubts and I'll edit it ( including removing this part when it does improve) after lunch.
Thanks in advance

Related

Django model relations and dividing models into few tables in larger project

I have few problems with Django models (relations mostly), but I'll start from code than make desciption and put questions...
Django models and relations in short (very simplified) version:
# Shorten version of services
SERVICES = [
("TC", "Tires Cleaning"),
("EC", "Exterior Cleaning"),
("IC", "Interior Cleaning"),
("CW", "Cleaning & Washing - full service"),
("WX", "Application of wax"),
]
class Client(models.Model):
name = models.CharField(max_length=35)
surname = models.CharField(max_length=35)
car = models.CharField(max_length=25)
class SingleService(models.Model):
service_name = models.CharField(max_length=35)
service_type = models.CharField(max_length=1, choices=SERVICES, default="CW")
price = models.IntegerField()
class SetOfServices(models.Model):
set_of_services = ????
price_of_set = ???
class Purchase(models.Model):
client = OneToOneField(client)
order = models.ForeignKey(SetOfServices, on_delete=models.CASCADE, blank=True, null=True)
price = ???
I want to make small project (Car Wash) with 8+ django models. Client is coming to car wash and I want to store its name/ surname and car make/model/type etc in DB
for future refference (clients coming back will get discount and free coffee).
Then I have SingleService model with about 20-30 services - they have different name and price because of diferernt tasks / time to make and options / extra features.
SetOfServices model must consist of few single services (custom, but customized from Django admin panel, probably only once, at setup / configuration time).
So it must be set of few services (I don't want client to buy only one / single service!), like:
Example SET 1:
Tires cleaning
+
Interior cleaning
Example SET 2:
Exterior cleaning
+
Application of wax
....and so on. I want to join few services in one set of services client can buy (with some discount - for example).
The last model (from above code, I plan to expand this project) is Purchase where Client orders one SetOfServices and pay some money.
The problems I encountered is choosing right relation for set_of_services field and how to calculate overall price of this set (price_of_set field).
Should I use ForeignKey (One to Many) relation in set_of_service field?
How to divide Django models (when project expands) into few tables in database (I am using PostgreSQL)? Could you give me refference or example code for it? I know we use db_table in Meta description of models, but how the relations change??
The question you want to ask yourself is:
Does one SetOfServices contain multiple SingleServices --> YES
Does one SingleService show up in multiple different SetOfServices? --> YES
If your result to these questions is two times YES the relationship is a many-to-many.
class SetOfServices(models.Model):
set_of_services = models.ManyToManyField(SingleService)
# price_of_set --> does this really need to be stored in database?
#property
def price_of_set(self):
return sum([service.price for service in self.set_of_services.all()])
Now you want to ask yourself:
Does a Purchase allow buying multiple SetOfServices (this is dependent on your choice)? --> NO
Is a SetOfServices bought by multiple Purchases? --> YES
YES YES --> ManyToMany
NO YES --> OneToMany --> ForeignKey
class Purchase(models.Model):
client = OneToOneField(client)
order = models.ForeignKey(SetOfServices, on_delete=models.CASCADE, blank=True, null=True)
# same advice as above for price = ???
#property
def price(self):
return self.order.price_of_set
To be honest I feel like your setup of models is already kinda stable. I can't tell you how to divide models at runtime of a project. I've never done it.
Let me know how it goes!
Edit after comment of OP
Depending on your "staring point" you can access the price inside of your templates. Here some examples:
<h1>Object = Purchase</h1>
{{ object.price }}
<h1>Object = SetOfServices</h1>
{{ object.price_of_set }}
<h1>Object = SingleService</h1>
{{ object.price }}

How could you make this really reaaally complicated raw SQL query with django's ORM?

Good day, everyone. Hope you're doing well. I'm a Django newbie, trying to learn the basics of RESTful development while helping in a small app project. Currently, there's a really difficult query that I must do to create a calculated field that updates my student's status accordingly to the time interval the classes are in. First, let me explain the models:
class StudentReport(models.Model):
student = models.ForeignKey(Student, on_delete=models.CASCADE,)
headroom_teacher = models.ForeignKey(Teacher, on_delete=models.CASCADE,)
upload = models.ForeignKey(Upload, on_delete=models.CASCADE, related_name='reports', blank=True, null=True,)
exams_date = models.DateTimeField(null=True, blank=True)
#Other fields that don't matter
class ExamCycle(models.Model):
student = models.ForeignKey(student, on_delete=models.CASCADE,)
headroom_teacher = models.ForeignKey(Teacher, on_delete=models.CASCADE,)
#Other fields that don't matter
class RecommendedClasses(models.Model):
report = models.ForeignKey(Report, on_delete=models.CASCADE,)
range_start = models.DateField(null=True)
range_end = models.DateField(null=True)
# Other fields that don't matter
class StudentStatus(models.TextChoices):
enrolled = 'enrolled' #started class
anxious_for_exams = 'anxious_for_exams'
sticked_with_it = 'sticked_with_it' #already passed one cycle
So this app will help the management of a Cram school. We first do an initial report of the student and its best/worst subjects in StudentReport. Then a RecommendedClasses object is created that tells him which clases he should enroll in. Finally, we have a cycle of exams (let's say 4 times a year). After he completes each exam, another report is created and he can be recommended a new class or to move on the next level of its previous class.
I'll use the choices in StudentStatus to calculate an annotated field that I will call status on my RecommendedClasses report model. I'm having issues with the sticked_with_it status because it's a query that it's done after one cycle is completed and two reports have been made (Two because this query must be done in StudentStatus, after 2nd Report is created). A 'sticked_with_it' student has a report created after exams_date where RecommendedClasses was created and the future exams_date time value falls within the 30 days before range_start and 60 days after the range_end values of the recommendation (Don't question this, it's just the way the higherups want the status)
I have already come up with two ways to do it, but one is with a RAW SQL query and the other is waaay to complicated and slow. Here it is:
SELECT rec.id AS rec_id FROM
school_recommendedclasses rec LEFT JOIN
school_report original_report
ON rec.report_id = original_report.id
AND rec.teacher_id = original_report.teacher_id
JOIN reports_report2 future_report
ON future_report.exams_date > original_report.exams_date
AND future_report.student_id = original_report.student_id
AND future_report.`exams_date` > (rec.`range_start` - INTERVAL 30 DAY)
AND future_report.`exams_date` <
(rec.`range_end` + INTERVAL 60 DAY)
AND original_report.student_id = future_report.student_id
How can I transfer this to a proper DJANGO ORM that is not so painfully unoptimized? I'll show you the other way in the comments.
FWIW, I find this easier to read, but there's very little wrong with your query.
Transforming this to your ORM should be straightforward, and any further optimisations are down to indexes...
SELECT r.id rec_id
FROM reports_recommendation r
JOIN reports_report2 o
ON o.id = r.report_id
AND o.provider_id = r.provider_id
JOIN reports_report2 f
ON f.initial_exam_date > o.initial_exam_date
AND f.patient_id = o.patient_id
AND f.initial_exam_date > r.range_start - INTERVAL 30 DAY
AND f.initial_exam_date < r.range_end + INTERVAL 60 DAY
AND f.provider_id = o.provider_id

Creating a query with foreign keys and grouping by some data in Django

I thought about my problem for days and i need a fresh view on this.
I am building a small application for a client for his deliveries.
# models.py - Clients app
class ClientPR(models.Model):
title = models.CharField(max_length=5,
choices=TITLE_LIST,
default='mr')
last_name = models.CharField(max_length=65)
first_name = models.CharField(max_length=65, verbose_name='Prénom')
frequency = WeekdayField(default=[]) # Return a CommaSeparatedIntegerField from 0 for Monday to 6 for Sunday...
[...]
# models.py - Delivery app
class Truck(models.Model):
name = models.CharField(max_length=40, verbose_name='Nom')
description = models.CharField(max_length=250, blank=True)
color = models.CharField(max_length=10,
choices=COLORS,
default='green',
unique=True,
verbose_name='Couleur Associée')
class Order(models.Model):
delivery = models.ForeignKey(OrderDelivery, verbose_name='Delivery')
client = models.ForeignKey(ClientPR)
order = models.PositiveSmallIntegerField()
class OrderDelivery(models.Model):
date = models.DateField(default=d.today())
truck = models.ForeignKey(Truck, verbose_name='Camion', unique_for_date="date")
So i was trying to get a query and i got this one :
ClientPR.objects.today().filter(order__delivery__date=date.today())
.order_by('order__delivery__truck', 'order__order')
But, i does not do what i really want.
I want to have a list of Client obj (query sets) group by truck and order by today's delivery order !
The thing is, i want to have EVERY clients for the day even if they are not in the delivery list and with filter, that cannot be it.
I can make a query with OrderDelivery model but i will only get the clients for the delivery, not all of them for the day...
Maybe i will need to do it with a Q object ? or even raw SQL ?
Maybe i have built my models relationships the wrong way ? Or i need to lower what i want to do... Well, for now, i need your help to see the problem with new eyes !
Thanks for those who will take some time to help me.
After some tests, i decided to go with 2 querys for one table.
One from OrderDelivery Queryset for getting a list of clients regroup by Trucks and another one from ClientPR Queryset for all the clients without a delivery set for them.
I that way, no problem !

Database design under Django

I have a probably quite basic question: I am currently setting up a database for students and their marks in my courses. I currently have two main classes in my models.py: Student (containing their name, id, email address etc) and Course (containing an id, the year it is running in and the assessment information - for example "Essay" "40%" "Presentation" "10%" "Exam" "50%"). And, of course, Student has a ManyToMany field so that I can assign students to courses and vice versa. I have to be able to add and modify these things.
Now, obviously, I would like to be able to add the marks for the students in the different assignments (which are different from course to course). As I am very unexperienced in database programming, I was hoping one of you could give me a tip how to set this up within my models.
Thanks,
Tobi
Perhaps the way to go about it is to have a separate class for assignment, something like this.
class Assignment(models.Model):
ASSIGNMENT_TYPES = (
('essay', "Essay"),
...
)
ASSIGNMENT_GRADES = (
('a+', "A+"),
('a', "A"),
...
)
student = models.ForeignKey("Student")
course = models.ForeignKey("Course")
assignment_type = models.CharField(choices=ASSIGNMENT_TYPES, max_length=15, default='essay')
progress = models.IntegerField()
grade = models.CharField(choices=ASSIGNMENT_GRADES, max_length=3, default="a+")
This way you have one assignment connected to one student and one course. It can be modified relatively easy if you have multiple students per one assignment, by adding another class (for example StudentGroup) and including it in the model.
Hope that this helps :)
Create a model called "Assessments", which has a foreign key to Course. In addition ,create a field called "Assessment Type", another called "Assessment Result" and a final one called "Assesment Date". Should look like this:
ASSESSMENTS = (('E','Essay'),('P','Presentation'))
class Assessment(models.MOdel):
course = models.ForeignKey('Course')
assessment = models.CharField(choices=ASESSMENTS)
result = models.CharField(max_length=250)
taken_on = models.DateField()
overall_result = models.BooleanField()
is_complete = models.BooleanField()
Each time there is an exam, you fill in a record in this table for each assessment taken. You can use the overall result as a flag to see if the student has passed or failed, and the is_complete to see if there are any exams pending for a course.
You should look at models.py file of classcomm,
a content management system written in Django for delivering and managing Courses on the Web.
It has following Models
Department
Course
Instructor
Mentor
Enrollment
Assignment
DueDateOverride
Submission
Grade
ExtraCredit
Information
Resource
Announcement
You may not need such a complex relationship for you case, but it's wort looking into it's models design.
You can find more details on homepage of this project.

What's the best way to ensure balanced transactions in a double-entry accounting app?

What's the best way to ensure that transactions are always balanced in double-entry accounting?
I'm creating a double-entry accounting app in Django. I have these models:
class Account(models.Model):
TYPE_CHOICES = (
('asset', 'Asset'),
('liability', 'Liability'),
('equity', 'Equity'),
('revenue', 'Revenue'),
('expense', 'Expense'),
)
num = models.IntegerField()
type = models.CharField(max_length=20, choices=TYPE_CHOICES, blank=False)
description = models.CharField(max_length=1000)
class Transaction(models.Model):
date = models.DateField()
description = models.CharField(max_length=1000)
notes = models.CharField(max_length=1000, blank=True)
class Entry(models.Model):
TYPE_CHOICES = (
('debit', 'Debit'),
('credit', 'Credit'),
)
transaction = models.ForeignKey(Transaction, related_name='entries')
type = models.CharField(max_length=10, choices=TYPE_CHOICES, blank=False)
account = models.ForeignKey(Account, related_name='entries')
amount = models.DecimalField(max_digits=11, decimal_places=2)
I'd like to enforce balanced transactions at the model level but there doesn't seem to be hooks in the right place. For example, Transaction.clean won't work because transactions get saved first, then entries are added due to the Entry.transaction ForeignKey.
I'd like balance checking to work within admin also. Currently, I use an EntryInlineFormSet with a clean method that checks balance in admin but this doesn't help when adding transactions from a script. I'm open to changing my models to make this easier.
(Hi Ryan! -- Steve Traugott)
It's been a while since you posted this, so I'm sure you're way past this puzzle. For others and posterity, I have to say yes, you need to be able to split transactions, and no, you don't want to take the naive approach and assume that transaction legs will always be in pairs, because they won't. You need to be able to do N-way splits, where N is any positive integer greater than 1. Ryan has the right structure here.
What Ryan calls Entry I usually call Leg, as in transaction leg, and I'm usually working with bare Python on top of some SQL database. I haven't used Django yet, but I'd be surprised (shocked) if Django doesn't support something like the following: Rather than use the native db row ID for transaction ID, I instead usually generate a unique transaction ID from some other source, store that in both the Transaction and Leg objects, do my final check to ensure debits and credits balance, and then commit both Transaction and Legs to the db in one SQL transaction.
Ryan, is that more or less what you wound up doing?
This may sound terribly naive, but why not just record each transaction in a single record containing "to account" and "from account" foreign keys that link to an accounts table instead of trying to create two records for each transaction? From my point of view, it seems that the essence of "double-entry" is that transactions always move money from one account to another. There is no advantage using two records to store such transactions and many disadvantages.