def load_article_transactions(article_no) -> Article: article = Article(article_no, get_article_name((article_no))) cursor = CONNECTION.cursor() cursor.execute(f''' SELECT [Shipment Date] Date, [Qty_ (Base)] Quantity, [Destination No_] customer_no, cu.Name customer_name FROM [ODC$Posted Whse_ Shipment Line] psl INNER JOIN [ODC$Customer] cu ON cu.[No_] = psl.[Destination No_] WHERE [Item No_] = '{article_no}' ORDER BY [Shipment Date] ''') for row in cursor: if article.customer_exists(row.customer_no): customer = article.get_customer(row.customer_no) else: customer = Customer(row.customer_no, row.customer_name) article.add_customer(customer) customer.add_transaction(row.Date, row.Quantity) return article
class TestCustomer(unittest.TestCase): def setUp(self): self.sut = Customer(id='1', transactions=[]) self.transactions = [i for i in range(1, 1000)] self.add_transactions() def test_should_add_transactions(self): self.assertEqual(self.sut.transactions, self.transactions) def test_should_return_min_transaction(self): self.assertEqual(self.sut.get_min_transaction(), min(self.transactions)) def test_should_return_max_transaction(self): self.assertEqual(self.sut.get_max_transaction(), max(self.transactions)) def test_should_return_mean(self): self.assertEqual(self.sut.get_max_transaction(), max(self.transactions)) def test_should_return_std(self): self.assertEqual(self.sut.get_max_transaction(), max(self.transactions)) def test_should_return_ratio(self): self.assertEqual(self.sut.get_ratio(amount=10), 10 / min(self.transactions)) def test_should_not_add_negative_transactions(self): for amount in range(1000): self.assertRaises(ValueError, self.sut.add_transaction, amount=-amount) # when no transaction is made def test_should_not_return_min_transaction(self): self.sut.transactions = [] self.assertRaises(ValueError, self.sut.get_min_transaction) def test_should_not_return_max_transaction(self): self.sut.transactions = [] self.assertRaises(ValueError, self.sut.get_max_transaction) def test_should_not_return_mean(self): self.sut.transactions = [] self.assertRaises(ValueError, self.sut.get_mean) def test_should_not_return_std(self): self.sut.transactions = [] self.assertRaises(ValueError, self.sut.get_std) def test_should_not_return_ration(self): self.sut.transactions = [] self.assertRaises(ValueError, self.sut.get_ratio, 10) def add_transactions(self): for amount in self.transactions: self.sut.add_transaction(amount=amount)
def detect_anomaly(self, customer_id, merchant_id, transaction_amount): # ignore negative or 0 amount if transaction_amount <= 0: return # check if customer already exists customer = self.customers.get(customer_id, None) if customer is None: # create a new customer and save it customer = Customer(id=customer_id, transactions=[]) self.customers.__setitem__(customer_id, customer) # use global mean/std until customer has < 10 transactions if len(customer.transactions) < 10: mean = self.global_mean std = self.global_std else: mean = customer.get_mean() std = customer.get_std() max_allowed_amount = mean + 3 * std if transaction_amount > max_allowed_amount: self.logging.warning({ 'customer_id': customer_id, 'merchant_id': merchant_id, 'transaction_amount': transaction_amount, 'max_allowed_amount': max_allowed_amount, 'prev_3_transactions': customer.transactions[-3:] }) customer.add_transaction(amount=transaction_amount) print( 'new transaction', { 'customer_id': customer_id, 'merchant_id': merchant_id, 'amount': transaction_amount })