Aller au contenu

# Schemas

## `NonEmptyStr = Annotated[str, MinLen(1)]` `module-attribute`

## `SimpleClubSchema`

Bases: `ModelSchema`

## `SimpleUserSchema`

Bases: `ModelSchema`

A schema with the minimum amount of information to represent a user.

## `Counter`

Bases: `Model`

### `gen_token()`

Generate a new token for this counter.

Source code in `counter/models.py`

    615
    616
    617
    618
    619
    620
    def gen_token(self) -> None:
        """Generate a new token for this counter."""
        self.token = "".join(
            random.choice(string.ascii_letters + string.digits) for _ in range(30)
        )
        self.save()

### `barmen_list()`

Returns the barman list as list of User.

Source code in `counter/models.py`

    622
    623
    624
    625
    626
    627
    @cached_property
    def barmen_list(self) -> list[User]:
        """Returns the barman list as list of User."""
        return [
            p.user for p in self.permanencies.filter(end=None).select_related("user")
        ]

### `get_random_barman()`

Return a random user being currently a barman.

Source code in `counter/models.py`

    629
    630
    631
    def get_random_barman(self) -> User:
        """Return a random user being currently a barman."""
        return random.choice(self.barmen_list)

### `update_activity()`

Update the barman activity to prevent timeout.

Source code in `counter/models.py`

    633
    634
    635
    def update_activity(self) -> None:
        """Update the barman activity to prevent timeout."""
        self.permanencies.filter(end=None).update(activity=timezone.now())

### `can_refill()`

Show if the counter authorize the refilling with physic money.

Source code in `counter/models.py`

    637
    638
    639
    640
    641
    642
    643
    def can_refill(self) -> bool:
        """Show if the counter authorize the refilling with physic money."""
        if self.type != "BAR":
            return False
        # at least one of the barmen is in the AE board
        ae = Club.objects.get(id=settings.SITH_MAIN_CLUB_ID)
        return any(ae.get_membership_for(barman) for barman in self.barmen_list)

### `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.

Each element of the QuerySet corresponds to a barman and has the following data

- the full name (first name + last name) of the barman
- the nickname of the barman
- the promo of the barman
- the total number of office hours the barman did attend

Source code in `counter/models.py`

    645
    646
    647
    648
    649
    650
    651
    652
    653
    654
    655
    656
    657
    658
    659
    660
    661
    662
    663
    664
    665
    def get_top_barmen(self) -> QuerySet:
        """Return a QuerySet querying the office hours stats of all the barmen of all time
        of this counter, ordered by descending number of hours.

        Each element of the QuerySet corresponds to a barman and has the following data :
            - the full name (first name + last name) of the barman
            - the nickname of the barman
            - the promo of the barman
            - the total number of office hours the barman did attend
        """
        name_expr = Concat(F("user__first_name"), Value(" "), F("user__last_name"))
        return (
            self.permanencies.exclude(end=None)
            .annotate(
                name=name_expr, nickname=F("user__nick_name"), promo=F("user__promo")
            )
            .values("user", "name", "nickname", "promo")
            .annotate(perm_sum=Sum(F("end") - F("start")))
            .exclude(perm_sum=None)
            .order_by("-perm_sum")
        )

### `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`

    667
    668
    669
    670
    671
    672
    673
    674
    675
    676
    677
    678
    679
    680
    681
    682
    683
    684
    685
    686
    687
    688
    689
    690
    691
    692
    693
    694
    695
    696
    697
    698
    699
    700
    701
    702
    703
    def get_top_customers(self, since: datetime | date | None = None) -> QuerySet:
        """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

        Args:
            since: timestamp from which to perform the calculation
        """
        if since is None:
            since = get_start_of_semester()
        if isinstance(since, date):
            since = datetime(since.year, since.month, since.day, tzinfo=tz.utc)
        name_expr = Concat(
            F("customer__user__first_name"), Value(" "), F("customer__user__last_name")
        )
        return (
            self.sellings.filter(date__gte=since)
            .annotate(
                name=name_expr,
                nickname=F("customer__user__nick_name"),
                promo=F("customer__user__promo"),
                user=F("customer__user"),
            )
            .values("user", "promo", "name", "nickname")
            .annotate(
                selling_sum=Sum(
                    F("unit_price") * F("quantity"), output_field=CurrencyField()
                )
            )
            .filter(selling_sum__gt=0)
            .order_by("-selling_sum")
        )

### `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`

    705
    706
    707
    708
    709
    710
    711
    712
    713
    714
    715
    716
    717
    718
    719
    720
    721
    722
    723
    724
    725
    726
    def get_total_sales(self, since: datetime | date | None = None) -> CurrencyField:
        """Compute and return the total turnover of this counter since the given date.

        By default, the date is the start of the current semester.

        Args:
            since: timestamp from which to perform the calculation

        Returns:
            Total revenue earned at this counter.
        """
        if since is None:
            since = get_start_of_semester()
        if isinstance(since, date):
            since = datetime(since.year, since.month, since.day, tzinfo=tz.utc)
        return self.sellings.filter(date__gte=since).aggregate(
            total=Sum(
                F("quantity") * F("unit_price"),
                default=0,
                output_field=CurrencyField(),
            )
        )["total"]

### `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`

    728
    729
    730
    731
    732
    733
    734
    def customer_is_barman(self, customer: Customer | User) -> bool:
        """Check if this counter is a `bar` and if the customer is currently logged in.
        This is useful to compute special prices."""

        # Customer and User are two different tables,
        # but they share the same primary key
        return self.type == "BAR" and any(b.pk == customer.pk for b in self.barmen_list)

## `Price`

Bases: `Model`

## `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`

    407
    408
    409
    410
    411
    412
    413
    def is_owned_by(self, user):
        """Method to see if that object can be edited by the given user."""
        if user.is_anonymous:
            return False
        return user.is_in_group(
            pk=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID
        ) or user.is_in_group(pk=settings.SITH_GROUP_COUNTER_ADMIN_ID)

## `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.

Source code in `counter/models.py`

    349
    350
    351
    352
    353
    def is_owned_by(self, user):
        """Method to see if that object can be edited by the given user."""
        if user.is_anonymous:
            return False
        return user.is_in_group(pk=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID)

## `CounterSchema`

Bases: `ModelSchema`

## `CounterFilterSchema`

Bases: `FilterSchema`

## `SimplifiedCounterSchema`

Bases: `ModelSchema`

## `ProductTypeSchema`

Bases: `ModelSchema`

## `SimpleProductTypeSchema`

Bases: `ModelSchema`

## `ReorderProductTypeSchema`

Bases: `Schema`

## `SimpleProductSchema`

Bases: `ModelSchema`

## `ProductPriceSchema`

Bases: `ModelSchema`

## `ProductSchema`

Bases: `ModelSchema`

## `ProductFilterSchema`

Bases: `FilterSchema`

## `SaleFilterSchema`

Bases: `FilterSchema`