diff --git a/backend/individual-assignment/src/OrderProcessor.js b/backend/individual-assignment/src/OrderProcessor.js new file mode 100644 index 00000000..f075f59b --- /dev/null +++ b/backend/individual-assignment/src/OrderProcessor.js @@ -0,0 +1,15 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.OrderProcessor = void 0; +class OrderProcessor { + constructor(shippingStrategy, paymentStrategy) { + this.shippingStrategy = shippingStrategy; + this.paymentStrategy = paymentStrategy; + } + processOrder(order) { + this.paymentStrategy.processPayment(order); + this.shippingStrategy.ship(order); + order.close(); + } +} +exports.OrderProcessor = OrderProcessor; diff --git a/backend/individual-assignment/src/OrderProcessor.ts b/backend/individual-assignment/src/OrderProcessor.ts new file mode 100644 index 00000000..e82f4f71 --- /dev/null +++ b/backend/individual-assignment/src/OrderProcessor.ts @@ -0,0 +1,16 @@ +import { Order } from './models/Order'; +import { PaymentStrategy } from './interfaces/PaymentStrategy'; +import { ShippingStrategy } from './interfaces/ShippingStrategy'; + +export class OrderProcessor { + constructor( + private shippingStrategy: ShippingStrategy, + private paymentStrategy: PaymentStrategy + ) {} + + processOrder(order: Order): void { + this.paymentStrategy.processPayment(order); + this.shippingStrategy.ship(order); + order.close(); + } +} diff --git a/backend/individual-assignment/src/SolutionDescription.md b/backend/individual-assignment/src/SolutionDescription.md new file mode 100644 index 00000000..24dc9066 --- /dev/null +++ b/backend/individual-assignment/src/SolutionDescription.md @@ -0,0 +1,59 @@ +# Alterações e Melhorias de Código: + +## As alterações no código visam aplicar um Design Orientado a Objetos e Princípios de Programação Orientada a Objetos, respeitando também as normas do SOLID para uma arquitetura limpa, flexível, escalável e de fácil manutenção! + +### 1. Separar as Responsábilidades + +O código inicial estava concentrado em uma única estrutura com os serviços dentro de metodos, como por exemplo, o metodo *pay* da classe *Order* que tinham diversas verificações, como tipo de produto, serviço de pagamento entre outros. + +Para separar as responsábilidades, foram adicionadas interfaces para: + +* PaymentStrategy; +* ShippingStrategy; +* ReceiptSender; +* DiscountVoucherApplier; +* PaymentMethod + +Essas interfaces são contratos que as classes que as implementarem seguirão, permitindo que cada forma de pagamento seja implementada em sua respectiva classe sem precisar modificar código para isso! +Para os serviços de pagamento e envios, foram criadas classes estrategicas que executam essas funções: + +* DigitalProductPayment; +* PhysicalProductShipping; +* BookShipping; +* DigitalDiscountVoucherApplier; +* DigitalReceiptSender; +* MembershipActivationShipping; +* PhysicalProductShipping; +* NoShipping; + +Essas classes, implementam as interfaces deixando o código mais dinamico e de fácil manutenção. + +### 2. Composição de Herança + +No código original a logica era embutida dentro das classes, então passamos a usar o princípio de composição de herança. + +Colocamos a classe *OrderProcessor* para organizar os pagamentos e enviar para as estrategias específicas de cada produto. + +Com isso, novas estrategias podem ser adicionadas sem alterar a classe *OrderProcessor*, facilitando a escalação do código e reduzindo o acoplamento, uma vez que as lógicas de pagamento e envio ficam sendo gerenciadas pelas estratégias. + +### 3. Separação de Lógicas Específicas + +Aplicando a responsábilidade única, criamos classes específicas para cada lógica (envio e pagamento de produtos físicos, digitais, livros e assinaturas), assim cada classe tem responsábilidade apenas com o seu serviço para o seu tipo de produto específico. + +Caso futuramente existam alterações nas lógicas específicas de algum tipo de produto, poderá ser implementada sem impactar nas outras classes do projeto. + +### 4. Metodos e Funcionalidades + +No código original, os serviços estavam sendo feitos diretamente na classe de pagamento, então foram criadas interfaces adicionais: + +* ReceiptSender; +* DigitalDiscountVoucherApplier; + +Elas definem os acordos que serão implementados nessas operações, ambas foram implementadas na classe *DigitalProductPayment* para realizar essa tarefa de enviar a descrição da compra para o email do cliente e conceder o voucher de desconto. + +Diferentes implementações de envio de recibos e aplicação de vouchers poderão ser usadas sem alterar a lógica de pagamento além de permitir que cada classe tenha apenas uma tarefa específica. + +#### Dentre as implementações realizadas, considero importante ressaltar o *"Open Closed Principle"* deixando todas as classes prontas e abertas para futuras implementações e melhorias mas fechadas para modificações. + +#### Estão sinalizados também os metodos onde as implementações de serviços como envio de e-mails, imprimir o shipping label, etc, devem ser feitas! + diff --git a/backend/individual-assignment/src/index.js b/backend/individual-assignment/src/index.js new file mode 100644 index 00000000..e5667e56 --- /dev/null +++ b/backend/individual-assignment/src/index.js @@ -0,0 +1,46 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const Order_1 = require("./models/Order"); +const Customer_1 = require("./models/Customer"); +const Address_1 = require("./models/Address"); +const Product_1 = require("./models/Product"); +const OrderProcessor_1 = require("./OrderProcessor"); +const DigitalProductPayment_1 = require("./strategies/DigitalProductPayment"); +const PhysicalProductShipping_1 = require("./strategies/PhysicalProductShipping"); +const BookShipping_1 = require("./strategies/BookShipping"); +const MembershipActivationShipping_1 = require("./strategies/MembershipActivationShipping"); +const NoShipping_1 = require("./strategies/NoShipping"); +const DigitalReceiptSender_1 = require("./strategies/DigitalReceiptSender"); +const DigitalDiscountVoucherApplier_1 = require("./strategies/DigitalDiscountVoucherApplier"); +// Exemplo de uso +const shirt = new Product_1.Product("Flowered t-shirt", Product_1.ProductType.PHYSICAL, 35.00); +const netflix = new Product_1.Product("Familiar plan", Product_1.ProductType.MEMBERSHIP, 29.90); +const book = new Product_1.Product("The Hitchhiker's Guide to the Galaxy", Product_1.ProductType.BOOK, 120.00); +const music = new Product_1.Product("Stairway to Heaven", Product_1.ProductType.DIGITAL, 5.00); +// Pedido de Produto Físico +const order1 = new Order_1.Order(new Customer_1.Customer(), new Address_1.Address()); +order1.addProduct(shirt, 2); +const physicalPaymentStrategy = new DigitalProductPayment_1.DigitalProductPayment(new DigitalReceiptSender_1.DigitalReceiptSender(), new DigitalDiscountVoucherApplier_1.DigitalDiscountVoucherApplier()); +const physicalShippingStrategy = new PhysicalProductShipping_1.PhysicalProductShipping(); +const orderProcessor1 = new OrderProcessor_1.OrderProcessor(physicalShippingStrategy, physicalPaymentStrategy); +orderProcessor1.processOrder(order1); +// Pedido de Assinatura de Serviço +const order2 = new Order_1.Order(new Customer_1.Customer(), new Address_1.Address()); +order2.addProduct(netflix, 1); +const membershipPaymentStrategy = new DigitalProductPayment_1.DigitalProductPayment(new DigitalReceiptSender_1.DigitalReceiptSender(), new DigitalDiscountVoucherApplier_1.DigitalDiscountVoucherApplier()); +const membershipShippingStrategy = new MembershipActivationShipping_1.MembershipActivationShipping(); +const orderProcessor2 = new OrderProcessor_1.OrderProcessor(membershipShippingStrategy, membershipPaymentStrategy); +orderProcessor2.processOrder(order2); +// Pedido de Livro +const order3 = new Order_1.Order(new Customer_1.Customer(), new Address_1.Address()); +order3.addProduct(book, 1); +const bookPaymentStrategy = new DigitalProductPayment_1.DigitalProductPayment(new DigitalReceiptSender_1.DigitalReceiptSender(), new DigitalDiscountVoucherApplier_1.DigitalDiscountVoucherApplier()); +const bookShippingStrategy = new BookShipping_1.BookShipping(); +const orderProcessor3 = new OrderProcessor_1.OrderProcessor(bookShippingStrategy, bookPaymentStrategy); +orderProcessor3.processOrder(order3); +// Pedido de Mídia Digital +const order4 = new Order_1.Order(new Customer_1.Customer(), new Address_1.Address()); +order4.addProduct(music, 1); +const digitalPaymentStrategy = new DigitalProductPayment_1.DigitalProductPayment(new DigitalReceiptSender_1.DigitalReceiptSender(), new DigitalDiscountVoucherApplier_1.DigitalDiscountVoucherApplier()); +const orderProcessor4 = new OrderProcessor_1.OrderProcessor(new NoShipping_1.NoShipping(), digitalPaymentStrategy); +orderProcessor4.processOrder(order4); diff --git a/backend/individual-assignment/src/index.ts b/backend/individual-assignment/src/index.ts new file mode 100644 index 00000000..6ea9a04a --- /dev/null +++ b/backend/individual-assignment/src/index.ts @@ -0,0 +1,69 @@ +import { Order } from './models/Order'; +import { Customer } from './models/Customer'; +import { Address } from './models/Address'; +import { Product, ProductType } from './models/Product'; +import { OrderProcessor } from './OrderProcessor'; +import { DigitalProductPayment } from './strategies/DigitalProductPayment'; +import { PhysicalProductShipping } from './strategies/PhysicalProductShipping'; +import { BookShipping } from './strategies/BookShipping'; +import { MembershipActivationShipping } from './strategies/MembershipActivationShipping'; +import { NoShipping } from './strategies/NoShipping'; +import { DigitalReceiptSender } from './strategies/DigitalReceiptSender'; +import { DigitalDiscountVoucherApplier } from './strategies/DigitalDiscountVoucherApplier'; + +// Exemplo de uso + +const shirt = new Product("Flowered t-shirt", ProductType.PHYSICAL, 35.00); +const netflix = new Product("Familiar plan", ProductType.MEMBERSHIP, 29.90); +const book = new Product("The Hitchhiker's Guide to the Galaxy", ProductType.BOOK, 120.00); +const music = new Product("Stairway to Heaven", ProductType.DIGITAL, 5.00); + +// Pedido de Produto Físico +const order1 = new Order(new Customer(), new Address()); +order1.addProduct(shirt, 2); + +const physicalPaymentStrategy = new DigitalProductPayment( + new DigitalReceiptSender(), + new DigitalDiscountVoucherApplier() +); +const physicalShippingStrategy = new PhysicalProductShipping(); + +const orderProcessor1 = new OrderProcessor(physicalShippingStrategy, physicalPaymentStrategy); +orderProcessor1.processOrder(order1); + +// Pedido de Assinatura de Serviço +const order2 = new Order(new Customer(), new Address()); +order2.addProduct(netflix, 1); + +const membershipPaymentStrategy = new DigitalProductPayment( + new DigitalReceiptSender(), + new DigitalDiscountVoucherApplier() +); +const membershipShippingStrategy = new MembershipActivationShipping(); + +const orderProcessor2 = new OrderProcessor(membershipShippingStrategy, membershipPaymentStrategy); +orderProcessor2.processOrder(order2); + +// Pedido de Livro +const order3 = new Order(new Customer(), new Address()); +order3.addProduct(book, 1); + +const bookPaymentStrategy = new DigitalProductPayment( + new DigitalReceiptSender(), + new DigitalDiscountVoucherApplier() +); +const bookShippingStrategy = new BookShipping(); + +const orderProcessor3 = new OrderProcessor(bookShippingStrategy, bookPaymentStrategy); +orderProcessor3.processOrder(order3); + +// Pedido de Mídia Digital +const order4 = new Order(new Customer(), new Address()); +order4.addProduct(music, 1); + +const digitalPaymentStrategy = new DigitalProductPayment( + new DigitalReceiptSender(), + new DigitalDiscountVoucherApplier() +); +const orderProcessor4 = new OrderProcessor(new NoShipping(), digitalPaymentStrategy); +orderProcessor4.processOrder(order4); diff --git a/backend/individual-assignment/src/interfaces/DiscountVoucherApplier.js b/backend/individual-assignment/src/interfaces/DiscountVoucherApplier.js new file mode 100644 index 00000000..c8ad2e54 --- /dev/null +++ b/backend/individual-assignment/src/interfaces/DiscountVoucherApplier.js @@ -0,0 +1,2 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/backend/individual-assignment/src/interfaces/DiscountVoucherApplier.ts b/backend/individual-assignment/src/interfaces/DiscountVoucherApplier.ts new file mode 100644 index 00000000..b9962065 --- /dev/null +++ b/backend/individual-assignment/src/interfaces/DiscountVoucherApplier.ts @@ -0,0 +1,5 @@ +import { Customer } from '../models/Customer'; + +export interface DiscountVoucherApplier { + applyDiscountVoucher(customer: Customer): void; +} diff --git a/backend/individual-assignment/src/interfaces/PaymentMethod.js b/backend/individual-assignment/src/interfaces/PaymentMethod.js new file mode 100644 index 00000000..c8ad2e54 --- /dev/null +++ b/backend/individual-assignment/src/interfaces/PaymentMethod.js @@ -0,0 +1,2 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/backend/individual-assignment/src/interfaces/PaymentMethod.ts b/backend/individual-assignment/src/interfaces/PaymentMethod.ts new file mode 100644 index 00000000..c5927002 --- /dev/null +++ b/backend/individual-assignment/src/interfaces/PaymentMethod.ts @@ -0,0 +1,3 @@ +export interface PaymentMethod { + // Interface para métodos de pagamento +} diff --git a/backend/individual-assignment/src/interfaces/PaymentStrategy.js b/backend/individual-assignment/src/interfaces/PaymentStrategy.js new file mode 100644 index 00000000..c8ad2e54 --- /dev/null +++ b/backend/individual-assignment/src/interfaces/PaymentStrategy.js @@ -0,0 +1,2 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/backend/individual-assignment/src/interfaces/PaymentStrategy.ts b/backend/individual-assignment/src/interfaces/PaymentStrategy.ts new file mode 100644 index 00000000..a7dbf687 --- /dev/null +++ b/backend/individual-assignment/src/interfaces/PaymentStrategy.ts @@ -0,0 +1,5 @@ +import { Order } from '../models/Order'; + +export interface PaymentStrategy { + processPayment(order: Order): void; +} diff --git a/backend/individual-assignment/src/interfaces/ReceiptSender.js b/backend/individual-assignment/src/interfaces/ReceiptSender.js new file mode 100644 index 00000000..c8ad2e54 --- /dev/null +++ b/backend/individual-assignment/src/interfaces/ReceiptSender.js @@ -0,0 +1,2 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/backend/individual-assignment/src/interfaces/ReceiptSender.ts b/backend/individual-assignment/src/interfaces/ReceiptSender.ts new file mode 100644 index 00000000..abf186a3 --- /dev/null +++ b/backend/individual-assignment/src/interfaces/ReceiptSender.ts @@ -0,0 +1,5 @@ +import { Customer } from '../models/Customer'; + +export interface ReceiptSender { + sendReceipt(customer: Customer): void; +} diff --git a/backend/individual-assignment/src/interfaces/ShippingStrategy.js b/backend/individual-assignment/src/interfaces/ShippingStrategy.js new file mode 100644 index 00000000..c8ad2e54 --- /dev/null +++ b/backend/individual-assignment/src/interfaces/ShippingStrategy.js @@ -0,0 +1,2 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/backend/individual-assignment/src/interfaces/ShippingStrategy.ts b/backend/individual-assignment/src/interfaces/ShippingStrategy.ts new file mode 100644 index 00000000..676dbc99 --- /dev/null +++ b/backend/individual-assignment/src/interfaces/ShippingStrategy.ts @@ -0,0 +1,5 @@ +import { Order } from '../models/Order'; + +export interface ShippingStrategy { + ship(order: Order): void; +} diff --git a/backend/individual-assignment/src/models/Address.js b/backend/individual-assignment/src/models/Address.js new file mode 100644 index 00000000..7e3bcdad --- /dev/null +++ b/backend/individual-assignment/src/models/Address.js @@ -0,0 +1,6 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.Address = void 0; +class Address { +} +exports.Address = Address; diff --git a/backend/individual-assignment/src/models/Address.ts b/backend/individual-assignment/src/models/Address.ts new file mode 100644 index 00000000..ca09c23b --- /dev/null +++ b/backend/individual-assignment/src/models/Address.ts @@ -0,0 +1 @@ +export class Address{} \ No newline at end of file diff --git a/backend/individual-assignment/src/models/CreditCard.js b/backend/individual-assignment/src/models/CreditCard.js new file mode 100644 index 00000000..b57ba612 --- /dev/null +++ b/backend/individual-assignment/src/models/CreditCard.js @@ -0,0 +1,9 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.CreditCard = void 0; +class CreditCard { + constructor(number) { + this.number = number; + } +} +exports.CreditCard = CreditCard; diff --git a/backend/individual-assignment/src/models/CreditCard.ts b/backend/individual-assignment/src/models/CreditCard.ts new file mode 100644 index 00000000..b3fc097b --- /dev/null +++ b/backend/individual-assignment/src/models/CreditCard.ts @@ -0,0 +1,5 @@ +import { PaymentMethod } from '../interfaces/PaymentMethod'; + +export class CreditCard implements PaymentMethod { + constructor(public number: string) {} +} diff --git a/backend/individual-assignment/src/models/Customer.js b/backend/individual-assignment/src/models/Customer.js new file mode 100644 index 00000000..9b4fb187 --- /dev/null +++ b/backend/individual-assignment/src/models/Customer.js @@ -0,0 +1,6 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.Customer = void 0; +class Customer { +} +exports.Customer = Customer; diff --git a/backend/individual-assignment/src/models/Customer.ts b/backend/individual-assignment/src/models/Customer.ts new file mode 100644 index 00000000..3d74863c --- /dev/null +++ b/backend/individual-assignment/src/models/Customer.ts @@ -0,0 +1 @@ +export class Customer {} \ No newline at end of file diff --git a/backend/individual-assignment/src/models/Invoice.js b/backend/individual-assignment/src/models/Invoice.js new file mode 100644 index 00000000..b9c1f939 --- /dev/null +++ b/backend/individual-assignment/src/models/Invoice.js @@ -0,0 +1,11 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.Invoice = void 0; +class Invoice { + constructor(order) { + this.order = order; + this.billingAddress = order.address; + this.shippingAddress = order.address; + } +} +exports.Invoice = Invoice; diff --git a/backend/individual-assignment/src/models/Invoice.ts b/backend/individual-assignment/src/models/Invoice.ts new file mode 100644 index 00000000..a9ae2072 --- /dev/null +++ b/backend/individual-assignment/src/models/Invoice.ts @@ -0,0 +1,12 @@ +import { Address } from './Address'; +import { Order } from './Order'; + +export class Invoice { + public billingAddress: Address; + public shippingAddress: Address; + + constructor(public order: Order) { + this.billingAddress = order.address; + this.shippingAddress = order.address; + } +} diff --git a/backend/individual-assignment/src/models/Order.js b/backend/individual-assignment/src/models/Order.js new file mode 100644 index 00000000..9d635a12 --- /dev/null +++ b/backend/individual-assignment/src/models/Order.js @@ -0,0 +1,27 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.Order = void 0; +const OrderItem_1 = require("./OrderItem"); +class Order { + constructor(customer, address) { + this.customer = customer; + this.address = address; + this.items = []; + this.closedAt = null; + this.payment = null; + } + get totalAmount() { + return this.items.reduce((sum, item) => sum + item.total, 0); + } + addProduct(product, quantity) { + const productAlreadyAdded = this.items.some(item => item.product === product); + if (productAlreadyAdded) { + throw new Error("The product has already been added. Change the amount if you want more."); + } + this.items.push(new OrderItem_1.OrderItem(product, quantity)); + } + close() { + this.closedAt = new Date(); + } +} +exports.Order = Order; diff --git a/backend/individual-assignment/src/models/Order.ts b/backend/individual-assignment/src/models/Order.ts new file mode 100644 index 00000000..bb417dfd --- /dev/null +++ b/backend/individual-assignment/src/models/Order.ts @@ -0,0 +1,44 @@ +import { OrderItem } from './OrderItem'; +import { Customer } from './Customer'; +import { Address } from './Address'; +import { Payment } from './Payment'; +import { Product } from './Product'; +import{PaymentStrategy} from '../interfaces/PaymentStrategy'; + +export class Order { + public items: OrderItem[] = []; + public closedAt: Date | null = null; + public payment: Payment | null = null; + + constructor(public customer: Customer, public address: Address) {} + + get totalAmount(): number { + return this.items.reduce((sum, item) => sum + item.total, 0); + } + + addProduct(product: Product, quantity: number): void { + const productAlreadyAdded = this.items.some(item => item.product === product); + if (productAlreadyAdded) { + throw new Error("The product has already been added. Change the amount if you want more."); + } + + this.items.push(new OrderItem(product, quantity)); + } + + pay(strategy: PaymentStrategy): void { + if (this.payment) { + throw new Error("The order has already been paid!"); + } + + if (this.items.length === 0) { + throw new Error("Empty order cannot be paid!"); + } + + strategy.processPayment(this); + this.close(); + } + + public close(): void { + this.closedAt = new Date(); + } +} diff --git a/backend/individual-assignment/src/models/OrderItem.js b/backend/individual-assignment/src/models/OrderItem.js new file mode 100644 index 00000000..54833a6d --- /dev/null +++ b/backend/individual-assignment/src/models/OrderItem.js @@ -0,0 +1,13 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.OrderItem = void 0; +class OrderItem { + constructor(product, quantity) { + this.product = product; + this.quantity = quantity; + } + get total() { + return this.product.price * this.quantity; + } +} +exports.OrderItem = OrderItem; diff --git a/backend/individual-assignment/src/models/OrderItem.ts b/backend/individual-assignment/src/models/OrderItem.ts new file mode 100644 index 00000000..633a3fb9 --- /dev/null +++ b/backend/individual-assignment/src/models/OrderItem.ts @@ -0,0 +1,9 @@ +import { Product } from './Product'; + +export class OrderItem { + constructor(public product: Product, public quantity: number) {} + + get total(): number { + return this.product.price * this.quantity; + } +} diff --git a/backend/individual-assignment/src/models/Payment.js b/backend/individual-assignment/src/models/Payment.js new file mode 100644 index 00000000..4553a049 --- /dev/null +++ b/backend/individual-assignment/src/models/Payment.js @@ -0,0 +1,15 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.Payment = void 0; +const Invoice_1 = require("./Invoice"); +class Payment { + constructor(order, paymentMethod) { + this.order = order; + this.paymentMethod = paymentMethod; + this.paidAt = new Date(); + this.authorizationNumber = this.paidAt.getTime(); + this.amount = order.totalAmount; + this.invoice = new Invoice_1.Invoice(order); + } +} +exports.Payment = Payment; diff --git a/backend/individual-assignment/src/models/Payment.ts b/backend/individual-assignment/src/models/Payment.ts new file mode 100644 index 00000000..4333e83d --- /dev/null +++ b/backend/individual-assignment/src/models/Payment.ts @@ -0,0 +1,17 @@ +import { Order } from './Order'; +import { PaymentMethod } from '../interfaces/PaymentMethod'; +import { Invoice } from './Invoice'; + +export class Payment { + public paidAt: Date; + public authorizationNumber: number; + public amount: number; + public invoice: Invoice; + + constructor(public order: Order, public paymentMethod: PaymentMethod) { + this.paidAt = new Date(); + this.authorizationNumber = this.paidAt.getTime(); + this.amount = order.totalAmount; + this.invoice = new Invoice(order); + } +} diff --git a/backend/individual-assignment/src/models/Product.js b/backend/individual-assignment/src/models/Product.js new file mode 100644 index 00000000..e37681dd --- /dev/null +++ b/backend/individual-assignment/src/models/Product.js @@ -0,0 +1,18 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.Product = exports.ProductType = void 0; +var ProductType; +(function (ProductType) { + ProductType["PHYSICAL"] = "PHYSICAL"; + ProductType["BOOK"] = "BOOK"; + ProductType["DIGITAL"] = "DIGITAL"; + ProductType["MEMBERSHIP"] = "MEMBERSHIP"; +})(ProductType || (exports.ProductType = ProductType = {})); +class Product { + constructor(name, type, price) { + this.name = name; + this.type = type; + this.price = price; + } +} +exports.Product = Product; diff --git a/backend/individual-assignment/src/models/Product.ts b/backend/individual-assignment/src/models/Product.ts new file mode 100644 index 00000000..2a4faf63 --- /dev/null +++ b/backend/individual-assignment/src/models/Product.ts @@ -0,0 +1,8 @@ +import { ProductType } from '../models/enum/ProductType'; + +export class Product { + constructor( + public name: string, + public type: ProductType, + public price: number) {} +} diff --git a/backend/individual-assignment/src/models/enum/ProductType.ts b/backend/individual-assignment/src/models/enum/ProductType.ts new file mode 100644 index 00000000..f43b7202 --- /dev/null +++ b/backend/individual-assignment/src/models/enum/ProductType.ts @@ -0,0 +1,6 @@ +export enum ProductType { + PHYSICAL = 'PHYSICAL', + BOOK = 'BOOK', + DIGITAL = 'DIGITAL', + MEMBERSHIP = 'MEMBERSHIP' +} \ No newline at end of file diff --git a/backend/individual-assignment/src/strategies/BookShipping.js b/backend/individual-assignment/src/strategies/BookShipping.js new file mode 100644 index 00000000..0db87125 --- /dev/null +++ b/backend/individual-assignment/src/strategies/BookShipping.js @@ -0,0 +1,10 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.BookShipping = void 0; +class BookShipping { + ship(order) { + console.log("Generating shipping label for book with tax exemption notice..."); + // Implementação para gerar etiqueta de envio com aviso de isenção + } +} +exports.BookShipping = BookShipping; diff --git a/backend/individual-assignment/src/strategies/BookShipping.ts b/backend/individual-assignment/src/strategies/BookShipping.ts new file mode 100644 index 00000000..e73ca0d2 --- /dev/null +++ b/backend/individual-assignment/src/strategies/BookShipping.ts @@ -0,0 +1,9 @@ +import { ShippingStrategy } from '../interfaces/ShippingStrategy'; +import { Order } from '../models/Order'; + +export class BookShipping implements ShippingStrategy { + ship(order: Order): void { + console.log("Generating shipping label for book with tax exemption notice..."); + // Implementação para gerar etiqueta de envio com aviso de isenção + } +} diff --git a/backend/individual-assignment/src/strategies/DigitalDiscountVoucherApplier.js b/backend/individual-assignment/src/strategies/DigitalDiscountVoucherApplier.js new file mode 100644 index 00000000..dbeee405 --- /dev/null +++ b/backend/individual-assignment/src/strategies/DigitalDiscountVoucherApplier.js @@ -0,0 +1,10 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.DigitalDiscountVoucherApplier = void 0; +class DigitalDiscountVoucherApplier { + applyDiscountVoucher(customer) { + console.log("Applying discount voucher to user..."); + // Implementação para conceder o voucher de desconto + } +} +exports.DigitalDiscountVoucherApplier = DigitalDiscountVoucherApplier; diff --git a/backend/individual-assignment/src/strategies/DigitalDiscountVoucherApplier.ts b/backend/individual-assignment/src/strategies/DigitalDiscountVoucherApplier.ts new file mode 100644 index 00000000..183876ad --- /dev/null +++ b/backend/individual-assignment/src/strategies/DigitalDiscountVoucherApplier.ts @@ -0,0 +1,9 @@ +import { DiscountVoucherApplier } from '../interfaces/DiscountVoucherApplier'; +import { Customer } from '../models/Customer'; + +export class DigitalDiscountVoucherApplier implements DiscountVoucherApplier { + applyDiscountVoucher(customer: Customer): void { + console.log("Applying discount voucher to user..."); + // Implementação para conceder o voucher de desconto + } +} diff --git a/backend/individual-assignment/src/strategies/DigitalProductPayment.js b/backend/individual-assignment/src/strategies/DigitalProductPayment.js new file mode 100644 index 00000000..5e9c5971 --- /dev/null +++ b/backend/individual-assignment/src/strategies/DigitalProductPayment.js @@ -0,0 +1,20 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.DigitalProductPayment = void 0; +const Payment_1 = require("../models/Payment"); +const CreditCard_1 = require("../models/CreditCard"); +class DigitalProductPayment { + constructor(receiptSender, voucherApplier) { + this.receiptSender = receiptSender; + this.voucherApplier = voucherApplier; + } + processPayment(order) { + if (!order.payment) { + order.payment = new Payment_1.Payment(order, new CreditCard_1.CreditCard("1234-5678-9012-3456")); + console.log("Processing digital product payment..."); + this.receiptSender.sendReceipt(order.customer); + this.voucherApplier.applyDiscountVoucher(order.customer); + } + } +} +exports.DigitalProductPayment = DigitalProductPayment; diff --git a/backend/individual-assignment/src/strategies/DigitalProductPayment.ts b/backend/individual-assignment/src/strategies/DigitalProductPayment.ts new file mode 100644 index 00000000..5ac7161a --- /dev/null +++ b/backend/individual-assignment/src/strategies/DigitalProductPayment.ts @@ -0,0 +1,22 @@ +import { PaymentStrategy } from '../interfaces/PaymentStrategy'; +import { ReceiptSender } from '../interfaces/ReceiptSender'; +import { DiscountVoucherApplier } from '../interfaces/DiscountVoucherApplier'; +import { Order } from '../models/Order'; +import { Payment } from '../models/Payment'; +import { CreditCard } from '../models/CreditCard'; + +export class DigitalProductPayment implements PaymentStrategy { + constructor( + private receiptSender: ReceiptSender, + private voucherApplier: DiscountVoucherApplier + ) {} + + processPayment(order: Order): void { + if (!order.payment) { + order.payment = new Payment(order, new CreditCard("1234-5678-9012-3456")); + console.log("Processing digital product payment..."); + this.receiptSender.sendReceipt(order.customer); + this.voucherApplier.applyDiscountVoucher(order.customer); + } + } +} diff --git a/backend/individual-assignment/src/strategies/DigitalReceiptSender.js b/backend/individual-assignment/src/strategies/DigitalReceiptSender.js new file mode 100644 index 00000000..1d4b1de2 --- /dev/null +++ b/backend/individual-assignment/src/strategies/DigitalReceiptSender.js @@ -0,0 +1,10 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.DigitalReceiptSender = void 0; +class DigitalReceiptSender { + sendReceipt(customer) { + console.log("Sending email receipt to user..."); + // Implementação para enviar e-mail + } +} +exports.DigitalReceiptSender = DigitalReceiptSender; diff --git a/backend/individual-assignment/src/strategies/DigitalReceiptSender.ts b/backend/individual-assignment/src/strategies/DigitalReceiptSender.ts new file mode 100644 index 00000000..69ff7551 --- /dev/null +++ b/backend/individual-assignment/src/strategies/DigitalReceiptSender.ts @@ -0,0 +1,9 @@ +import { ReceiptSender } from '../interfaces/ReceiptSender'; +import { Customer } from '../models/Customer'; + +export class DigitalReceiptSender implements ReceiptSender { + sendReceipt(customer: Customer): void { + console.log("Sending email receipt to user..."); + // Implementação para enviar e-mail + } +} diff --git a/backend/individual-assignment/src/strategies/MembershipActivationShipping.js b/backend/individual-assignment/src/strategies/MembershipActivationShipping.js new file mode 100644 index 00000000..426183dc --- /dev/null +++ b/backend/individual-assignment/src/strategies/MembershipActivationShipping.js @@ -0,0 +1,10 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.MembershipActivationShipping = void 0; +class MembershipActivationShipping { + ship(order) { + console.log("Activating membership and sending notification email..."); + // Implementação para ativar assinatura e enviar e-mail + } +} +exports.MembershipActivationShipping = MembershipActivationShipping; diff --git a/backend/individual-assignment/src/strategies/MembershipActivationShipping.ts b/backend/individual-assignment/src/strategies/MembershipActivationShipping.ts new file mode 100644 index 00000000..3345cdca --- /dev/null +++ b/backend/individual-assignment/src/strategies/MembershipActivationShipping.ts @@ -0,0 +1,9 @@ +import { ShippingStrategy } from '../interfaces/ShippingStrategy'; +import { Order } from '../models/Order'; + +export class MembershipActivationShipping implements ShippingStrategy { + ship(order: Order): void { + console.log("Activating membership and sending notification email..."); + // Implementação para ativar assinatura e enviar e-mail + } +} diff --git a/backend/individual-assignment/src/strategies/NoShipping.js b/backend/individual-assignment/src/strategies/NoShipping.js new file mode 100644 index 00000000..b3948e8d --- /dev/null +++ b/backend/individual-assignment/src/strategies/NoShipping.js @@ -0,0 +1,9 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.NoShipping = void 0; +class NoShipping { + ship(order) { + console.log("No shipping required for this product type."); + } +} +exports.NoShipping = NoShipping; diff --git a/backend/individual-assignment/src/strategies/NoShipping.ts b/backend/individual-assignment/src/strategies/NoShipping.ts new file mode 100644 index 00000000..86cf51d6 --- /dev/null +++ b/backend/individual-assignment/src/strategies/NoShipping.ts @@ -0,0 +1,8 @@ +import { ShippingStrategy } from '../interfaces/ShippingStrategy'; +import { Order } from '../models/Order'; + +export class NoShipping implements ShippingStrategy { + ship(order: Order): void { + console.log("No shipping required for this product type."); + } +} diff --git a/backend/individual-assignment/src/strategies/PhysicalProductShipping.js b/backend/individual-assignment/src/strategies/PhysicalProductShipping.js new file mode 100644 index 00000000..7a659e7c --- /dev/null +++ b/backend/individual-assignment/src/strategies/PhysicalProductShipping.js @@ -0,0 +1,10 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.PhysicalProductShipping = void 0; +class PhysicalProductShipping { + ship(order) { + console.log("Generating shipping label for physical product..."); + // Implementação para gerar etiqueta de envio + } +} +exports.PhysicalProductShipping = PhysicalProductShipping; diff --git a/backend/individual-assignment/src/strategies/PhysicalProductShipping.ts b/backend/individual-assignment/src/strategies/PhysicalProductShipping.ts new file mode 100644 index 00000000..715e0dde --- /dev/null +++ b/backend/individual-assignment/src/strategies/PhysicalProductShipping.ts @@ -0,0 +1,9 @@ +import { ShippingStrategy } from '../interfaces/ShippingStrategy'; +import { Order } from '../models/Order'; + +export class PhysicalProductShipping implements ShippingStrategy { + ship(order: Order): void { + console.log("Generating shipping label for physical product..."); + // Implementação para gerar etiqueta de envio + } +}