✅ Решения заданий

⚠️ Рекомендация: попробуйте решить задания самостоятельно.

⚡ Кратко

Полные решения — в 💻 Примерах и 🏠 Домашнем задании.

Решение задачи 1. Система чеков

# practice18_receipts.py
class Receipt:
    def __init__(self, receipt_id: int, amount: float) -> None:
        self.id = receipt_id
        self.amount = amount

    def __str__(self) -> str:
        return f"{self.__class__.__name__} {self.id}: {self.amount}"


class SaleReceipt(Receipt):
    def __init__(self, receipt_id: int, amount: float) -> None:
        if amount <= 0:
            raise ValueError("SaleReceipt amount must be positive.")
        super().__init__(receipt_id, amount)

    def __str__(self) -> str:
        return f"{self.__class__.__name__} {self.id}: +{self.amount}"


class ReturnReceipt(Receipt):
    def __init__(self, receipt_id: int, amount: float) -> None:
        if amount >= 0:
            raise ValueError("ReturnReceipt amount must be negative.")
        super().__init__(receipt_id, amount)

    def __str__(self) -> str:
        return f"{self.__class__.__name__} {self.id}: {self.amount}"


class Shift:
    _id_counter = 1

    def __init__(self) -> None:
        self.id = Shift._id_counter
        Shift._id_counter += 1
        self.receipts: list[Receipt] = []
        self.closed = False

    def is_closed(self) -> bool:
        return self.closed

    def close(self) -> None:
        self.closed = True

    def add_receipt(self, amount: float) -> None:
        if self.closed:
            raise ValueError("Cannot add receipt to closed shift.")
        receipt_id = len(self.receipts) + 1
        self.receipts.append(SaleReceipt(receipt_id, amount))

    def add_return(self, source_shift: "Shift", original_id: int, return_amount: float) -> None:
        if not (0 < original_id <= len(source_shift.receipts)):
            raise ValueError("Original receipt not found.")
        original = source_shift.receipts[original_id - 1]
        if return_amount > original.amount:
            raise ValueError("Return amount exceeds original.")
        receipt_id = len(self.receipts) + 1
        self.receipts.append(ReturnReceipt(receipt_id, -return_amount))

    def list_receipts(self, receipt_type: str | None = None) -> None:
        for receipt in self.receipts:
            if receipt_type is None:
                print(receipt)
            elif receipt_type == "sale" and isinstance(receipt, SaleReceipt):
                print(receipt)
            elif receipt_type == "return" and isinstance(receipt, ReturnReceipt):
                print(receipt)

    def get_total(self, receipt_type: str | None = None) -> float:
        if receipt_type is None:
            return sum(r.amount for r in self.receipts)
        cls = SaleReceipt if receipt_type == "sale" else ReturnReceipt
        return sum(r.amount for r in self.receipts if isinstance(r, cls))


# --- проверка ---
shift1 = Shift()
shift1.add_receipt(100)
shift1.add_receipt(200)

shift2 = Shift()
shift2.add_return(shift1, 1, 50)

shift1.list_receipts()
shift2.list_receipts()
print("Total sales:", shift2.get_total("sale"))
print("Total returns:", shift2.get_total("return"))
print("Total:", shift2.get_total())

try:
    shift2.add_return(shift1, 1, 500)
except ValueError as e:
    print("Error:", e)

Решение задачи 2. Уведомления

# practice18_notifications.py
class EmailNotifyMixin:
    def email_notify(self, message: str) -> None:
        if not hasattr(self, "email"):
            raise AttributeError("Missing 'email'")
        print(f"Email to {self.email}: {message}")


class SmsNotifyMixin:
    def sms_notify(self, message: str) -> None:
        if not hasattr(self, "phone"):
            raise AttributeError("Missing 'phone'")
        print(f"SMS to {self.phone}: {message}")


class PushNotifyMixin:
    def push_notify(self, message: str) -> None:
        print(f"Push notification: {message}")


class User:
    def __init__(self, name: str) -> None:
        self.name = name


class Courier(User, EmailNotifyMixin, SmsNotifyMixin):
    def __init__(self, name: str, email: str, phone: str) -> None:
        super().__init__(name)
        self.email = email
        self.phone = phone

    def notify(self, message: str) -> None:
        self.email_notify(message)
        self.sms_notify(message)


class Admin(User, PushNotifyMixin):
    def notify(self, message: str) -> None:
        self.push_notify(message)


courier = Courier("Alice", "alice@example.com", "+123456789")
courier.notify("Package delivered.")

admin = Admin("Bob")
admin.notify("New report available.")