Покупка многих продуктов одновременно в интернет-магазине - PullRequest
0 голосов
/ 31 января 2012

Довольно просто запрограммировать только один продукт для продажи через мою платежную систему (api.payson.se), но покупка многих продуктов одновременно в различных количествах представляла для меня проблему, поскольку он не был реализован, а я - нет.иметь хорошую идею, как это сделать.Теперь у меня есть решение, которое я только что собрал, которое работает, но процесс моделирования и управления довольно быстрый и грязный, и я задаюсь вопросом, является ли это приемлемым или нужно переписать.Теперь система ведет себя так, что я могу войти в магазин (шаг 1) и ввести суммы для продуктов, которые я хочу купить

enter image description here

Затем, если я нажму кнопку «Купить» («Köp»)) мой Python вычисляет сумму правильно, и это работает при любой комбинации сумм и продуктов, о которых я говорю, что это общая сумма, и на этой странице также может быть указана спецификация, но она еще не реализована: enter image description here Общая сумма в шведской валюте является правильной ион написал заказ в мое хранилище данных со статусом «неоплаченный» и в котором указано, какие продукты заказаны и какую сумму для каждого продукта в хранилище данных: enter image description here Пользователь может либо отменить покупку, либо продолжить и фактически оплатить через платежную систему.api.payson.se: enter image description here Так что все, что мне нужно сделать, это прослушать ответ от Payson и обновить статус заказов, которые были оплачены.Но мое решение не выглядит очень чистым, и мне интересно, могу ли я продолжать с таким кодом, модель данных состоит из двух списков строк, один с суммами и один с каким продуктом (идентификатор товара), поскольку это был самый простой способ, который я мог решитьэто, но это тогда не напрямую доступно и только из списков.Есть ли лучшая модель данных, которую я могу использовать?

Код, который выполняет обработку, немного запутан и может использовать лучшую модель данных и лучший алгоритм, чем просто строки и списки:

class ShopHandler(NewBaseHandler):

    @user_required
    def get(self):
        user = \
            auth_models.User.get_by_id(long(self.auth.get_user_by_session()['user_id'
                ]))
        self.render_jinja('shop.htm', items=Item.recent(), user=user)
        return ''

    @user_required
    def post(self, command):
        user = \
            auth_models.User.get_by_id(long(self.auth.get_user_by_session()['user_id'
                ]))
        logging.info('in shophandler http post item id'+self.request.get('item'))

        items = [ self.request.get('items[1]'),self.request.get('items[2]'),self.request.get('items[3]'),self.request.get('items[4]'),self.request.get('items[5]'),self.request.get('items[6]'),self.request.get('items[7]'),self.request.get('items[8]')   ]   

        amounts = [ self.request.get('amounts[1]'),self.request.get('amounts[2]'),self.request.get('amounts[3]'),self.request.get('amounts[4]'),self.request.get('amounts[5]'),self.request.get('amounts[6]'),self.request.get('amounts[7]'),self.request.get('amounts[8]')  ]
        total = 0
        total = int(self.request.get('amounts[1]'))* long(Item.get_by_id(long(self.request.get('items[1]'))).price_fraction()) if self.request.get('amounts[1]') else total
        total = total + int(self.request.get('amounts[2]'))* long(Item.get_by_id(long(self.request.get('items[2]'))).price_fraction()) if self.request.get('amounts[2]') else total
        total = total + int(self.request.get('amounts[3]'))* long(Item.get_by_id(long(self.request.get('items[3]'))).price_fraction()) if self.request.get('amounts[3]') else total
        total = total + int(self.request.get('amounts[4]'))* long(Item.get_by_id(long(self.request.get('items[4]'))).price_fraction()) if self.request.get('amounts[4]') else total
        total = total + int(self.request.get('amounts[5]'))* long(Item.get_by_id(long(self.request.get('items[5]'))).price_fraction()) if self.request.get('amounts[5]') else total
        total = total + int(self.request.get('amounts[6]'))* long(Item.get_by_id(long(self.request.get('items[6]'))).price_fraction()) if self.request.get('amounts[6]') else total
        total = total + int(self.request.get('amounts[7]'))* long(Item.get_by_id(long(self.request.get('items[7]'))).price_fraction()) if self.request.get('amounts[7]') else total
        total = total + int(self.request.get('amounts[8]'))* long(Item.get_by_id(long(self.request.get('items[8]'))).price_fraction()) if self.request.get('amounts[8]') else total
        logging.info('total:'+str(total))
        trimmed = str(total)+',00'
        order = model.Order(status='UNPAID')
        order.items = items
        order.amounts = amounts
        order.put()
        logging.info('order was written')
        ExtraCost = 0
        GuaranteeOffered = 2
        OkUrl = 'http://' + self.request.host + r'/paysonreceive/'
        Key = '3110fb33-6122-4032-b25a-329b430de6b6'
        text = 'niklasro@gmail.com' + ':' + str(trimmed) + ':' + str(ExtraCost) \
            + ':' + OkUrl + ':' + str(GuaranteeOffered) + Key
        m = hashlib.md5()

        BuyerEmail = user.email
        AgentID = 11366
        self.render_jinja('order.htm', order=order, user=user, total=total, Generated_MD5_Hash_Value = hashlib.md5(text).hexdigest(), BuyerEmail=user.email, Description='Bnano Webshop', trimmed=trimmed, OkUrl=OkUrl, BuyerFirstName=user.firstname, BuyerLastName=user.lastname)

Моя модель для заказа, в которой используются не все поля,

class Order(db.Model):
  '''a transaction'''
  item = db.ReferenceProperty(Item)
  items = db.StringListProperty()
  amounts = db.StringListProperty()
  owner = db.UserProperty()
  purchaser = db.UserProperty()
  created = db.DateTimeProperty(auto_now_add=True)
  status = db.StringProperty( choices=( 'NEW', 'CREATED', 'ERROR', 'CANCELLED', 'RETURNED', 'COMPLETED', 'UNPAID', 'PAID' ) )
  status_detail = db.StringProperty()
  reference = db.StringProperty()
  secret = db.StringProperty() # to verify return_url
  debug_request = db.TextProperty()
  debug_response = db.TextProperty()
  paykey = db.StringProperty()
  shipping = db.TextProperty()

И модель для продукта, то есть элемента:

class Item(db.Model):
  '''an item for sale'''
  owner = db.UserProperty() #optional
  created = db.DateTimeProperty(auto_now_add=True)
  title = db.StringProperty(required=True)
  price = db.IntegerProperty() # cents / fractions, use price_decimal to get price in dollar / wholes
  image = db.BlobProperty()
  enabled = db.BooleanProperty(default=True)
  silver = db.IntegerProperty() #number of silver

  def price_dollars( self ):
    return self.price / 100.0

  def price_fraction( self ):
    return self.price / 100.0

  def price_silver( self ): #number of silvers an item "is worth"
    return self.silver / 1000.000

  def price_decimal( self ):
    return decimal.Decimal( str( self.price / 100.0 ) )

  def price_display( self ):
    return str(self.price_fraction()).replace('.',',')

  @staticmethod
  def recent():
    return Item.all().filter( "enabled =", True ).order('-created').fetch(10)

Я думаю, у вас есть идеячто происходит и что этот вид работает на пользователя, но код выглядит не очень хорошо.Как вы думаете, я могу оставить такой код и продолжить и сохранить это «решение», или я должен переписать его, чтобы сделать его более правильным?В магазине всего 8 товаров, и с этим решением становится трудно добавить новый Предмет для продажи, так как тогда я должен перепрограммировать сценарий, который не идеален.

Не могли бы вы прокомментировать или ответить, я быочень рад получить отзыв об этом быстром и грязном решении для моего варианта использования.

Спасибо

Обновление

Я переписал, чтобы добавить новые продукты иследующее кажется лучше предыдущего:

class ShopHandler(NewBaseHandler):

    @user_required
    def get(self):
        user = \
            auth_models.User.get_by_id(long(self.auth.get_user_by_session()['user_id'
                ]))
        self.render_jinja('shop.htm', items=Item.recent(), user=user)
        return ''

    @user_required
    def post(self, command):
        user = \
            auth_models.User.get_by_id(long(self.auth.get_user_by_session()['user_id'
                ]))
        logging.info('in shophandler http post')

        total = 0
        order = model.Order(status='UNPAID')

        for item in self.request.POST:
            amount = self.request.POST[item]
            logging.info('item:'+str(item))
            purchase = Item.get_by_id(long(item))
            order.items.append(purchase.key())
            order.amounts.append(int(amount))
            order.put()
            price = purchase.price_fraction()
            logging.info('amount:'+str(amount))
            logging.info('product price:'+str(price))
            total = total + price*int(amount)

        logging.info('total:'+str(total))
        order.total = str(total)
        order.put()
        trimmed = str(total).replace('.',',') + '0'
        ExtraCost = 0
        GuaranteeOffered = 2
        OkUrl = 'http://' + self.request.host + r'/paysonreceive/'
        Key = '6230fb54-7842-3456-b43a-349b340de3b8'
        text = 'niklasro@gmail.com' + ':' + str(trimmed) + ':' \
            + str(ExtraCost) + ':' + OkUrl + ':' \
            + str(GuaranteeOffered) + Key
        m = hashlib.md5()
        BuyerEmail = user.email  # if user.email else user.auth_id[0]
        AgentID = 11366
        self.render_jinja(
            'order.htm',
            order=order,
            user=user,
            total=total,
            Generated_MD5_Hash_Value=hashlib.md5(text).hexdigest(),
            BuyerEmail=user.email,
            Description='Bnano Webshop',
            trimmed=trimmed,
            OkUrl=OkUrl,
            BuyerFirstName=user.firstname,
            BuyerLastName=user.lastname,
            )

Ответы [ 2 ]

1 голос
/ 01 февраля 2012

Я попытаюсь сосредоточиться на одной очень очевидной проблеме с вашим кодом, но есть много проблем, с которыми я не собираюсь вникать. Мой совет - остановиться прямо сейчас. Вы внедряете платежную систему через Интернет. Вы действительно должны оставить это людям с большими навыками и опытом. «Интернет» - это довольно сложная вещь, чтобы правильно понять, обеспечивая безопасность, но система онлайн-платежей - это то, за что хорошо оплачиваются хорошо оплачиваемые консультанты с многолетним опытом, и им все же удается ошибиться довольно часто. Вы открываете для себя большую юридическую ответственность.

Если вы все еще не уверены, прочитайте Обучающее руководство по Python от обложки до обложки, возможно, несколько раз. Python - это язык, совершенно отличающийся от того классического языка ООП, в который вы мысленно втиснулись. После этого хотя бы пролистайте другую документацию. Если у вас возникли проблемы с этим, возьмите книгу О'Рейли по Python; подход к нему под другим углом должен помочь. После того, как вы сделали все это (и, может быть, одновременно), напишите как можно больше кода, который не приведет к тому, что вас забьют, если вы сделаете это неправильно. Тогда возможно вы можете написать систему заказов / оплаты.

Извините, если это звучит грубо, но миру больше не нужны плохие интернет-магазины; 1999 год позаботился об этом для нас.

В любом случае, к вашему коду: D Когда вы пишете что-то повторяющееся и копируемое, как это:

items = [ self.request.get('items[1]'),self.request.get('items[2]'),self.request.get('items[3]'),self.request.get('items[4]'),self.request.get('items[5]'),self.request.get('items[6]'),self.request.get('items[7]'),self.request.get('items[8]')   ]

Вы должны подумать про себя: «Подождите секунду! Повторяющиеся задачи - это именно то, для чего предназначены компьютеры». Вы могли бы заставить свой текстовый редактор делать это (см. Vim Macros), но лаконичный (но не слишком лаконичный) код всегда лучше длинного кода, так как вы делаете его быстрее поддерживаемым, менее подверженным ошибкам программиста и легче отлаживаемым , не говоря уже о том, сколько времени вы экономите, не копируя и не вставляя, поэтому давайте улучшим код.

Вот как я бы пересмотрел это в Python (продвинутые программисты делают это в своих головах или просто пропускают до конца):

#1. with a for loop
MAX_ITEMS = 8
items = []
for i in range(MAX_ITEMS):
    items.append(self.request.get('items[{}]'.format(i + 1))

#2. with a list comprehension
MAX_ITEMS = 8
items = [self.request.get('items[{}]'.format(i + 1)) for i in range(MAX_ITEMS)]

На самом деле, ограничение количества предметов довольно любительское и только разочарует ваших пользователей. Вы можете исправить это так:

items = []
i = 0
while True:
    try:
        items.append(self.request[i + 1]) #attempt to get the next item
    except IndexError as exc: #but if it fails...
        break #we must be at the last one
    i += 1

Я думаю, что вы должны оставить это сейчас, потому что это ясно, но не повторяется. Однако вы можете сократить его еще больше, используя функции из модуля itertools .

Несколько быстрых советов:

  • Избегайте конкатенации строк, особенно когда речь идет о предоставленных пользователем строках, особенно когда речь идет о предоставленных пользователем строках из Интернета. Используйте форматирование str.format и "%d" % (5,). БОНУС: Вам не нужно конвертировать все в строки!
  • Извлеките эти константы (например, ExtraCost = 2) из середины и поместите их в безопасное место (вверху модуля или в специальный файл в пакете)
  • Вы слишком доверяете пользователю way : на for item in self.request.POST: вы предполагаете, что все в запросе будет предметом, и вы делаете ноль проверку.
  • Пожалуйста, пожалуйста, пожалуйста. Никогда отключить автозаполнение. Я действительно не знаю, почему этот атрибут существует, кроме как раздражать.
1 голос
/ 31 января 2012

Чувак, это действительно странный код.Если вы хотите добавить новые товары в свой магазин, вы должны переписать скрипт вашего магазина.При первом отсоединении ваших товаров от интерфейса вы должны отправить POST-запрос контроллеру с вашими идентификаторами и количеством предметов, я не знаю, как работает объект gae request, но это должно быть так: со страницы вашего заказа сделайте POST-запрос с указанием элементовкоторый действительно нужен {"item_id": "qnt"}.В контроллере вы можете выбрать все объекты, такие как:

for item, qnt in request.POST:
    {do something with each item, for example where you can sum total}

и т. Д. Не связывайте контроллеры с вашими интерфейсами напрямую.Вы должны написать больше кода абстракции, если хотите создать действительно гибкое приложение.

...