Models
PAYMENT_METHOD = [('CHECK', _('Check')), ('CASH', _('Cash')), ('CARD', _('Credit card'))]
module-attribute
¶
CurrencyField(*args, **kwargs)
¶
Club
¶
Bases: Model
The Club class, made as a tree to allow nice tidy organization.
check_loop()
¶
Raise a validation error when a loop is found within the parent list.
Source code in club/models.py
is_owned_by(user)
¶
can_be_edited_by(user)
¶
can_be_viewed_by(user)
¶
Method to see if that object can be seen by the given user.
get_membership_for(user)
¶
Return the current membership the given user.
Note
The result is cached.
Source code in club/models.py
ResizedImageField(width=None, height=None, force_format=None, **kwargs)
¶
Bases: ImageField
A field that automatically resizes images to a given size.
This field is useful for profile pictures or product icons, for example.
The final size of the image is determined by the width and height parameters :
- If both are given, the image will be resized to fit in a rectangle of width x height
- If only one is given, the other will be calculated to keep the same ratio
If the force_format parameter is given, the image will be converted to this format.
Examples:
To resize an image with a height of 100px, without changing the ratio, and a format of WEBP :
To explicitly resize an image to 100x100px (but possibly change the ratio) :
Raises:
Type | Description |
---|---|
FieldError
|
If neither width nor height is given |
Parameters:
Name | Type | Description | Default |
---|---|---|---|
width
|
int | None
|
If given, the width of the resized image |
None
|
height
|
int | None
|
If given, the height of the resized image |
None
|
force_format
|
str | None
|
If given, the image will be converted to this format |
None
|
Source code in core/fields.py
Group
¶
Bases: Group
Implement both RealGroups and Meta groups.
Groups are sorted by their is_meta property
Notification
¶
Bases: Model
User
¶
Bases: AbstractUser
Defines the base user class, useable in every app.
This is almost the same as the auth module AbstractUser since it inherits from it, but some fields are required, and the username is generated automatically with the name of the user (see generate_username()).
Added field: nick_name, date_of_birth Required fields: email, first_name, last_name, date_of_birth
cached_groups: list[Group]
property
¶
Get the list of groups this user is in.
The result is cached for the default duration (should be 5 minutes)
Returns: A list of all the groups this user is in.
is_in_group(*, pk=None, name=None)
¶
Check if this user is in the given group. Either a group id or a group name must be provided. If both are passed, only the id will be considered.
The group will be fetched using the given parameter. If no group is found, return False. If a group is found, check if this user is in the latter.
Returns:
Type | Description |
---|---|
bool
|
True if the user is the group, else False |
Source code in core/models.py
age()
¶
Return the age this user has the day the method is called. If the user has not filled his age, return 0.
Source code in core/models.py
get_short_name()
¶
get_display_name()
¶
Returns the display name of the user.
A nickname if possible, otherwise, the full name.
get_age()
¶
get_family(godfathers_depth=4, godchildren_depth=4)
¶
Get the family of the user, with the given depth.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
godfathers_depth
|
NonNegativeInt
|
The number of generations of godfathers to fetch |
4
|
godchildren_depth
|
NonNegativeInt
|
The number of generations of godchildren to fetch |
4
|
Returns:
Type | Description |
---|---|
set[through]
|
A list of family relationships in this user's family |
Source code in core/models.py
email_user(subject, message, from_email=None, **kwargs)
¶
Sends an email to this User.
generate_username()
¶
Generates a unique username based on the first and last names.
For example: Guy Carlier gives gcarlier, and gcarlier1 if the first one exists.
Returns:
Type | Description |
---|---|
str
|
The generated username. |
Source code in core/models.py
is_owner(obj)
¶
Determine if the object is owned by the user.
Source code in core/models.py
can_edit(obj)
¶
Determine if the object can be edited by the user.
Source code in core/models.py
can_view(obj)
¶
Determine if the object can be viewed by the user.
Source code in core/models.py
clubs_with_rights()
¶
The list of clubs where the user has rights
CustomerQuerySet
¶
Bases: QuerySet
update_amount()
¶
Update the amount of all customers selected by this queryset.
The result is given as the sum of all refills minus the sum of all purchases.
Returns:
Type | Description |
---|---|
int
|
The number of updated rows. |
Source code in counter/models.py
Customer
¶
Bases: Model
Customer data of a User.
It adds some basic customers' information, such as the account ID, and is used by other accounting classes as reference to the customer, rather than using User.
can_buy: bool
property
¶
Check if whether this customer has the right to purchase any item.
This must be not confused with the Product.can_be_sold_to(user) method as the present method returns an information about a customer whereas the other tells something about the relation between a User (not a Customer, don't mix them) and a Product.
save(*args, allow_negative=False, is_selling=False, **kwargs)
¶
is_selling : tell if the current action is a selling allow_negative : ignored if not a selling. Allow a selling to put the account in negative Those two parameters avoid blocking the save method of a customer if his account is negative.
Source code in counter/models.py
get_or_create(user)
classmethod
¶
Work in pretty much the same way as the usual get_or_create method, but with the default field replaced by some under the hood.
If the user has an account, return it as is. Else create a new account with no money on it and a new unique account id
Example : ::
user = User.objects.get(pk=1)
account, created = Customer.get_or_create(user)
if created:
print(f"created a new account with id {account.id}")
else:
print(f"user has already an account, with {account.id} € on it"
Source code in counter/models.py
BillingInfo
¶
Bases: Model
Represent the billing information of a user, which are required by the 3D-Secure v2 system used by the etransaction module.
to_3dsv2_xml()
¶
Convert the data from this model into a xml usable
by the online paying service of the Crédit Agricole bank.
see : https://www.ca-moncommerce.com/espace-client-mon-commerce/up2pay-e-transactions/ma-documentation/manuel-dintegration-focus-3ds-v2/principes-generaux/#integration-3dsv2-developpeur-webmaster
.
Source code in counter/models.py
AccountDumpQuerySet
¶
AccountDump
¶
Bases: Model
The process of dumping an account.
ProductType
¶
Bases: OrderedModel
A product type.
Useful only for categorizing.
is_owned_by(user)
¶
Method to see if that object can be edited by the given user.
Product
¶
Bases: Model
A product, with all its related information.
is_owned_by(user)
¶
Method to see if that object can be edited by the given user.
Source code in counter/models.py
can_be_sold_to(user)
¶
Check if whether the user given in parameter has the right to buy this product or not.
This must be not confused with the Customer.can_buy() method as the present method returns an information about the relation between a User and a Product, whereas the other tells something about a Customer (and not a user, they are not the same model).
Returns:
Type | Description |
---|---|
bool
|
True if the user can buy this product else False |
Warning
This performs a db query, thus you can quickly have a N+1 queries problem if you call it in a loop. Hopefully, you can avoid that if you prefetch the buying_groups :
Source code in counter/models.py
CounterQuerySet
¶
Bases: QuerySet
annotate_has_barman(user)
¶
Annotate the queryset with the user_is_barman
field.
For each counter, this field has value True if the user is a barman of this counter, else False.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
user
|
User
|
the user we want to check if he is a barman |
required |
Examples:
sli = User.objects.get(username="sli")
counters = (
Counter.objects
.annotate_has_barman(sli) # add the user_has_barman boolean field
.filter(has_annotated_barman=True) # keep only counters where this user is barman
)
print("Sli est barman dans les comptoirs suivants :")
for counter in counters:
print(f"- {counter.name}")
Source code in counter/models.py
annotate_is_open()
¶
Annotate tue queryset with the is_open
field.
For each counter, if is_open=True
, then the counter is currently opened.
Else the counter is closed.
Source code in counter/models.py
handle_timeout()
¶
Disconnect the barmen who are inactive in the given counters.
Returns:
Type | Description |
---|---|
int
|
The number of affected rows (ie, the number of timeouted permanences) |
Source code in counter/models.py
Counter
¶
Bases: Model
gen_token()
¶
barmen_list()
¶
get_random_barman()
¶
update_activity()
¶
can_refill()
¶
Show if the counter authorize the refilling with physic money.
Source code in counter/models.py
get_top_barmen()
¶
Return a QuerySet querying the office hours stats of all the barmen of all time of this counter, ordered by descending number of hours.
Source code in counter/models.py
get_top_customers(since=None)
¶
Return a QuerySet querying the money spent by customers of this counter since the specified date, ordered by descending amount of money spent.
Each element of the QuerySet corresponds to a customer and has the following data :
- the full name (first name + last name) of the customer
- the nickname of the customer
- the amount of money spent by the customer
Parameters:
Name | Type | Description | Default |
---|---|---|---|
since
|
datetime | date | None
|
timestamp from which to perform the calculation |
None
|
Source code in counter/models.py
get_total_sales(since=None)
¶
Compute and return the total turnover of this counter since the given date.
By default, the date is the start of the current semester.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
since
|
datetime | date | None
|
timestamp from which to perform the calculation |
None
|
Returns:
Type | Description |
---|---|
CurrencyField
|
Total revenue earned at this counter. |
Source code in counter/models.py
customer_is_barman(customer)
¶
Check if this counter is a bar
and if the customer is currently logged in.
This is useful to compute special prices.
Source code in counter/models.py
RefillingQuerySet
¶
Bases: QuerySet
annotate_total()
¶
Annotate the Queryset with the total amount.
The total is just the sum of the amounts for each row.
If no grouping is involved (like in most queries),
this is just the same as doing nothing and fetching the
amount
attribute.
However, it may be useful when there is a group by
clause
in the query, or when other models are queried and having
a common interface is helpful (e.g. Selling.objects.annotate_total()
and Refilling.objects.annotate_total()
will both have the total
field).
Source code in counter/models.py
Refilling
¶
Bases: Model
Handle the refilling.
SellingQuerySet
¶
Bases: QuerySet
annotate_total()
¶
Annotate the Queryset with the total amount of the sales.
The total is considered as the sum of (unit_price * quantity).
Selling
¶
Bases: Model
Handle the sellings.
save(*args, allow_negative=False, **kwargs)
¶
allow_negative : Allow this selling to use more money than available for this user.
Source code in counter/models.py
Permanency
¶
Bases: Model
A permanency of a barman, on a counter.
This aims at storing a traceability of who was barman where and when.
Mainly for dick size contest establishing the top 10 barmen of the semester.
CashRegisterSummary
¶
Bases: Model
is_owned_by(user)
¶
Method to see if that object can be edited by the given user.
CashRegisterSummaryItem
¶
Bases: Model
Eticket
¶
Bases: Model
Eticket can be linked to a product an allows PDF generation.
is_owned_by(user)
¶
Method to see if that object can be edited by the given user.
StudentCard
¶
Bases: Model
Alternative way to connect a customer into a counter.
We are using Mifare DESFire EV1 specs since it's used for izly cards https://www.nxp.com/docs/en/application-note/AN10927.pdf UID is 7 byte long that means 14 hexa characters.
get_start_of_semester(today=None)
¶
Return the date of the start of the semester of the given date. If no date is given, return the start date of the current semester.
The current semester is computed as follows:
- If the date is between 15/08 and 31/12 => Autumn semester.
- If the date is between 01/01 and 15/02 => Autumn semester of the previous year.
- If the date is between 15/02 and 15/08 => Spring semester
Parameters:
Name | Type | Description | Default |
---|---|---|---|
today
|
date | None
|
the date to use to compute the semester. If None, use today's date. |
None
|
Returns:
Type | Description |
---|---|
date
|
the date of the start of the semester |