From 76122b891765f0af1301cd777f8e5023a96d4a2c Mon Sep 17 00:00:00 2001 From: Steve Waterworth Date: Fri, 26 Jan 2018 16:01:39 +0000 Subject: [PATCH] payment finished --- cart/server.js | 31 +++++++++++++++++++++++- docker-compose.yaml | 8 +++++++ payment/Dockerfile | 2 +- payment/docker-compose.yaml | 14 +++++++++++ payment/payment.py | 18 +++++++++++++- payment/rabbitmq.py | 48 +++++++++++++++++++++++++++++++++++++ payment/requirements.txt | 1 + web/static/css/style.css | 19 +++++++++++++++ web/static/js/controller.js | 24 ++++++++++++++++++- web/static/payment.html | 12 ++++++---- 10 files changed, 169 insertions(+), 8 deletions(-) create mode 100644 payment/docker-compose.yaml create mode 100644 payment/rabbitmq.py diff --git a/cart/server.js b/cart/server.js index 17dafe8..d9f7f56 100644 --- a/cart/server.js +++ b/cart/server.js @@ -50,6 +50,22 @@ app.get('/cart/:id', (req, res) => { }); }); +// delete cart with id +app.delete('/cart/:id', (req, res) => { + redisClient.del(req.params.id, (err, data) => { + if(err) { + console.log('ERROR', err); + res.status(500).send(err); + } else { + if(data == 1) { + res.send('OK'); + } else { + res.status(404).send('cart not found'); + } + } + }); +}); + // update/create cart app.get('/add/:id/:sku/:qty', (req, res) => { // check quantity @@ -184,7 +200,20 @@ app.post('/shipping/:id', (req, res) => { price: shipping.cost, subtotal: shipping.cost }; - cart.items.push(item); + // check shipping already in the cart + var idx; + var len = cart.items.length; + for(idx = 0; idx < len; idx++) { + if(cart.items[idx].sku == item.sku) { + break; + } + } + if(idx == len) { + // not already in cart + cart.items.push(item); + } else { + cart.items[idx] = item; + } cart.total = calcTotal(cart.items); // work out tax cart.tax = calcTax(cart.total); diff --git a/docker-compose.yaml b/docker-compose.yaml index ace5990..2cb3ee0 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -14,6 +14,12 @@ services: - "6379" networks: - robot-shop + rabbitmq: + image: rabbitmq:3.7-alpine + ports: + - "5672" + networks: + - robot-shop catalogue: build: context: catalogue @@ -67,6 +73,8 @@ services: build: context: payment image: steveww/rs-payment + depends_on: + - rabbitmq ports: - "8080" networks: diff --git a/payment/Dockerfile b/payment/Dockerfile index 46843f8..4d22dd0 100644 --- a/payment/Dockerfile +++ b/payment/Dockerfile @@ -8,6 +8,6 @@ COPY requirements.txt /app/ RUN pip install -r requirements.txt -COPY payment.py /app/ +COPY *.py /app/ CMD ["python", "payment.py"] diff --git a/payment/docker-compose.yaml b/payment/docker-compose.yaml new file mode 100644 index 0000000..6055018 --- /dev/null +++ b/payment/docker-compose.yaml @@ -0,0 +1,14 @@ +version: '3' +services: + rabbitmq: + image: rabbitmq:3.7-alpine + ports: + - "5672" + payment: + build: + context: . + image: steveww/rs-payment + depends_on: + - rabbitmq + ports: + - "8080:8080" diff --git a/payment/payment.py b/payment/payment.py index 8154479..1944fa5 100644 --- a/payment/payment.py +++ b/payment/payment.py @@ -1,9 +1,13 @@ import os import sys +import time import logging +import uuid import requests from flask import Flask from flask import request +from flask import jsonify +from rabbitmq import Publisher app = Flask(__name__) @@ -21,9 +25,21 @@ def pay(id): req = requests.get('https://paypal.com/') app.logger.info('paypal returned {}'.format(req.status_code)) + # Generate order id + orderid = str(uuid.uuid4()) + queueOrder({ 'order': orderid, 'cart': cart }) + # TDOD - order history - return 'OK' + return jsonify({ 'order': orderid }) + + +def queueOrder(order): + app.logger.info('queue order') + publisher.publish(order) + +# RabbitMQ +publisher = Publisher(app.logger) if __name__ == "__main__": sh = logging.StreamHandler(sys.stdout) diff --git a/payment/rabbitmq.py b/payment/rabbitmq.py new file mode 100644 index 0000000..8353168 --- /dev/null +++ b/payment/rabbitmq.py @@ -0,0 +1,48 @@ +import json +import pika + +class Publisher: + HOST = 'rabbitmq' + VIRTUAL_HOST = '/' + EXCHANGE='robot-shop' + TYPE='direct' + ROUTING_KEY = 'orders' + + def __init__(self, logger): + self._logger = logger + self._params = pika.connection.ConnectionParameters( + host=self.HOST, + virtual_host=self.VIRTUAL_HOST, + credentials=pika.credentials.PlainCredentials('guest', 'guest')) + self._conn = None + self._channel = None + + def _connect(self): + if not self._conn or self._conn.is_closed: + self._conn = pika.BlockingConnection(self._params) + self._channel = self._conn.channel() + self._channel.exchange_declare(exchange=self.EXCHANGE, exchange_type=self.TYPE) + self._logger.info('connected to broker') + + def _publish(self, msg): + self._channel.basic_publish(exchange=self.EXCHANGE, + routing_key=self.ROUTING_KEY, + body=json.dumps(msg).encode()) + self._logger.info('message sent') + + #Publish msg, reconnecting if necessary. + def publish(self, msg): + if self._channel is None: + self._connect() + try: + self._publish(msg) + except pika.exceptions.ConnectionClosed: + self._logger.info('reconnecting to queue') + self._connect() + self._publish(msg) + + def close(self): + if self._conn and self._conn.is_open: + self._logger.info('closing queue connection') + self._conn.close() + diff --git a/payment/requirements.txt b/payment/requirements.txt index c1c6c9d..754aa12 100644 --- a/payment/requirements.txt +++ b/payment/requirements.txt @@ -1,3 +1,4 @@ Flask requests +pika instana diff --git a/web/static/css/style.css b/web/static/css/style.css index ce4eaa6..41f3851 100644 --- a/web/static/css/style.css +++ b/web/static/css/style.css @@ -154,3 +154,22 @@ table.credentials { text-align: right; } +/* payment */ +a.cont:visited { + color: cyan; + text-decoration: none; + font-weight: bold; +} + +a.cont:link { + color: cyan; + text-decoration: none; + font-weight: bold; +} + +a.cont:hover { + color: white; + text-decoration: none; + font-weight: bold; +} + diff --git a/web/static/js/controller.js b/web/static/js/controller.js index f8d7f34..99831d0 100644 --- a/web/static/js/controller.js +++ b/web/static/js/controller.js @@ -316,18 +316,40 @@ robotshop.controller('paymentform', function($scope, $http, currentUser) { $scope.data = {}; + $scope.data.message = ' '; + $scope.data.buttonDisabled = false; + $scope.data.cont = false; $scope.data.uniqueid = currentUser.uniqueid; $scope.data.cart = currentUser.cart; $scope.pay = function() { + $scope.data.buttonDisabled = true; $http({ url: '/api/payment/pay/' + $scope.data.uniqueid, method: 'POST', data: $scope.data.cart }).then((res) => { - console.log('payment ok'); + console.log('order', res.data); + $scope.data.message = 'Order placed ' + res.data.orderid; + // clear down cart + $scope.data.cart = { + total: 0, + items: [] + }; + currentUser.cart = $scope.data.cart; + $scope.data.cont = true; + $http({ + url: '/api/cart/cart/' + $scope.data.uniqueid, + method: 'DELETE' + }).then((res) => { + console.log('cart deleted ok'); + }).catch((e) => { + console.log('ERROR cart delete', e); + }); }).catch((e) => { console.log('ERROR', e); + $scope.data.message = 'ERROR placing order'; + $scope.data.buttonDisabled = false; }); }; diff --git a/web/static/payment.html b/web/static/payment.html index 20f458b..f23935c 100644 --- a/web/static/payment.html +++ b/web/static/payment.html @@ -1,9 +1,6 @@

Review your order

-
- Your cart is empty, get shopping -
@@ -31,9 +28,16 @@
- +
+
+ {{ data.message }} +
+
+ Thankyou for your order + Continue shopping +