func (item *Item) Ship(user string, qty uint64, timestamp string) (*Shipment, bool, error) {
	// Create a reproducible ID based on input data (hence the timestamp)
	hash := services.MakeHash(user, item.Name, qty, timestamp)
	shipment := item.catalog.MakeShipment(hash)

	if err := shipment.lock.Lock(); err != nil {
		return nil, false, fmt.Errorf("Failed to lock shipment: %v", err)
	}
	defer shipment.unlock()

	existed, err := shipment.LoadExisting()
	if err != nil {
		return nil, false, err
	}

	if !existed {
		shipment.User = user
		shipment.Item = item.Name
		shipment.Quantity = qty
		shipment.Status = catalogApi.ShipmentCreated
		if err = shipment.Save(); err != nil {
			return nil, false, err
		}
	}
	return shipment, existed, nil
}
func (payments *Payments) NewPayment(username string, value float64, timestamp string) (*Payment, bool, error) {
	// Create a reproducible ID based on input data (hence the timestamp)
	hash := services.MakeHash(username, value, timestamp)

	// Try to fetch an existing payment
	payment := payments.MakePayment(hash)
	existed, err := payment.LoadExisting(true, false)
	if err != nil {
		return nil, false, err
	}
	defer payment.unlock()

	// Create the payment, if it did not exist
	if !existed {
		payment.User = username
		payment.Value = value
		payment.TransactionId = ""
		payment.setStatus(PaymentCreated)
		if err = payment.Save(); err != nil {
			return nil, false, err
		}
	}

	// Now try to create the remote transaction
	if err = payment.advance(PaymentPending); err != nil {
		return nil, false, err
	} else {
		return payment, existed, nil
	}
}
func (shop *Shop) noteFreshOrder(username string, item string, qty uint64) error {
	hash := services.MakeHash(username, item, qty)
	resp := shop.redis.Cmd("set", fresh_orders_key+hash, shop.redisLockValue, "ex", fresh_order_timeout_sec, "nx")
	if err := resp.Err(); err != nil {
		return err
	}
	if str, _ := resp.Str(); resp.HasResult() && str == "OK" {
		return nil
	} else {
		// The same order has been submitted within fresh_order_timeout
		return fmt.Errorf("Order rejected: duplicate order suspected")
	}
}