Ejemplo n.º 1
0
func (engine *Engine) CreateOrder(order *data.Order) error {

	if order.ID != 0 {
		return ErrNonEmptyID
	}

	if order.State == "" {
		order.State = data.OrderStateDraft
	} else if order.State != data.OrderStateDraft {
		return ErrNotDraft
	}

	if order.Time == 0 {
		order.Time = uint64(time.Now().UTC().Unix())
	} else if order.Time < uint64(time.Now().UTC().Add(-PastTimeTreshold).Unix()) {
		return ErrIsPast
	}

	tx, err := engine.storage.Begin()
	if err != nil {
		return err
	}

	if err := tx.CreateOrder(order); err != nil {
		return tx.Rollback(err)
	}

	populate.Order(order)

	if err := tx.Commit(); err != nil {
		return err
	}

	return nil
}
Ejemplo n.º 2
0
func TestForestCreateOrder(t *testing.T) {

	_time := uint64(time.Now().UTC().Unix())

	expected := data.Order{
		State: data.OrderStateDraft,
		Time:  _time,
	}
	populate.Order(&expected)

	payload := data.Order{
		Time: _time,
	}

	got := data.Order{}

	r := getForestClient().POST(t, forest.Path("/orders/{}", "").Content(payload, MimeJSON))

	forest.ExpectStatus(t, r, http.StatusCreated)

	forest.ExpectJSONDocument(t, r, &got)

	expected.ID = got.ID

	if !reflect.DeepEqual(got, expected) {
		t.Errorf("Got: %s\n\nExpected: %s", testutils.JSON(got), testutils.JSON(expected))
	}

}
Ejemplo n.º 3
0
func TestForestOrderItemCreateOrderPlaced(t *testing.T) {

	productInOrder := data.Product{
		Name: generateName("Product"),
		Price: data.Price{
			Vat: 20,
			Net: 100,
		},
	}

	createProduct(&productInOrder)

	product := data.Product{
		Name: generateName("Product"),
		Price: data.Price{
			Vat: 20,
			Net: 100,
		},
	}

	createProduct(&product)

	order := data.Order{
		Items: []data.OrderItem{
			data.OrderItem{
				Product:  productInOrder,
				Quantity: 1,
			},
		},
	}

	createOrder(&order)

	order.State = data.OrderStatePlaced

	updateOrder(&order)

	payload := data.OrderItem{
		Product: data.Product{
			ID: product.ID,
		},
		Quantity: 0,
	}

	got := Error{}

	r := getForestClient().POST(t, forest.Path("/orders/{orderID}/items/{}", order.ID, "").Content(payload, MimeJSON))

	// TODO:
	// forest.ExpectStatus(t, r, http.StatusForbidden)
	forest.ExpectStatus(t, r, http.StatusInternalServerError)

	forest.ExpectJSONDocument(t, r, &got)

	if got.Message == "" {
		t.Error("Got empty error message")
	}

}
Ejemplo n.º 4
0
func (engine *Engine) UpdateOrder(order *data.Order) error {

	if order.ID == 0 {
		return ErrEmptyID
	}

	tx, err := engine.storage.Begin()
	if err != nil {
		return err
	}

	existingOrder := &data.Order{
		ID: order.ID,
	}

	if err := tx.LoadOrder(existingOrder); err != nil {
		return tx.Rollback(err)
	}

	if order.Time == 0 {
		order.Time = existingOrder.Time
	} else if order.Time < uint64(time.Now().UTC().Add(-PastTimeTreshold).Unix()) {
		return tx.Rollback(ErrIsPast)
	}

	if order.State == "" {
		order.State = existingOrder.State
	} else if order.State != existingOrder.State {
		if existingOrder.State != data.OrderStateDraft {
			return tx.Rollback(ErrNotDraft)
		}
		switch order.State {
		case data.OrderStatePlaced:
			if len(existingOrder.Items) < 1 {
				return tx.Rollback(ErrOrderEmpty)
			}
		case data.OrderStateCancelled:
		default:
			return tx.Rollback(ErrUnknownState)
		}
	}

	if err := tx.UpdateOrder(order); err != nil {
		return tx.Rollback(err)
	}

	populate.Order(order)

	if err := tx.Commit(); err != nil {
		return err
	}

	return nil
}
Ejemplo n.º 5
0
func TestForestCreateOrderWithItems(t *testing.T) {

	_time := uint64(time.Now().UTC().Unix())

	expected := data.Order{
		State: data.OrderStateDraft,
		Time:  _time,
	}

	payload := data.Order{
		Time: _time,
	}

	for i := 1; i <= 3; i++ {

		product := data.Product{
			Name: generateName("Product"),
			Price: data.Price{
				Vat: 20,
				Net: uint64(100 * i),
			},
		}

		createProduct(&product)

		item := data.OrderItem{
			Product:  product,
			Quantity: uint64(i),
		}

		// newest come first:
		payload.Items = append([]data.OrderItem{item}, payload.Items...)
		expected.Items = append([]data.OrderItem{item}, expected.Items...)

	}

	populate.Order(&expected)

	got := data.Order{}

	r := getForestClient().POST(t, forest.Path("/orders/{}", "").Content(payload, MimeJSON))

	forest.ExpectStatus(t, r, http.StatusCreated)

	forest.ExpectJSONDocument(t, r, &got)

	expected.ID = got.ID

	if !reflect.DeepEqual(got, expected) {
		t.Errorf("Got: %s\n\nExpected: %s", testutils.JSON(got), testutils.JSON(expected))
	}

}
Ejemplo n.º 6
0
func TestForestRemoveOrderItemOrderPlaced(t *testing.T) {

	productInOrder := data.Product{
		Name: generateName("Product"),
		Price: data.Price{
			Vat: 20,
			Net: 100,
		},
	}

	createProduct(&productInOrder)

	product := data.Product{
		Name: generateName("Product"),
		Price: data.Price{
			Vat: 20,
			Net: 100,
		},
	}

	createProduct(&product)

	order := data.Order{
		Items: []data.OrderItem{
			data.OrderItem{
				Product:  productInOrder,
				Quantity: 1,
			},
		},
	}

	createOrder(&order)

	order.State = data.OrderStatePlaced

	updateOrder(&order)

	got := Error{}

	r := getForestClient().DELETE(t, forest.Path("/orders/{orderID}/items/{productID}", order.ID, product.ID))

	// TODO:
	// forest.ExpectStatus(t, r, http.StatusNotFound)
	forest.ExpectStatus(t, r, http.StatusInternalServerError)

	forest.ExpectJSONDocument(t, r, &got)

	if got.Message == "" {
		t.Error("Got empty error message")
	}

}
Ejemplo n.º 7
0
func TestForestListOrderItems(t *testing.T) {

	order := data.Order{}

	for i := 1; i <= 3; i++ {

		product := data.Product{
			Name: generateName("Product"),
			Price: data.Price{
				Vat: 20,
				Net: 100,
			},
		}

		createProduct(&product)

		item := data.OrderItem{
			Product:  product,
			Quantity: 1,
		}

		order.Items = append([]data.OrderItem{item}, order.Items...)

	}

	createOrder(&order)

	expected := order.Items

	got := []data.OrderItem{}

	r := getForestClient().GET(t, forest.Path("/orders/{orderID}/items/{}", order.ID, "").Query("limit", len(expected)))

	forest.ExpectStatus(t, r, http.StatusOK)

	forest.ExpectJSONDocument(t, r, &got)

	if !reflect.DeepEqual(got, expected) {
		t.Errorf("Got: %s\n\nExpected: %s", testutils.JSON(got), testutils.JSON(expected))
	}

}
Ejemplo n.º 8
0
func Order(order *data.Order) {

	order.Price.Vat = 0
	order.Price.Net = 0
	order.Price.Gross = 0

	if order.Items == nil {
		order.Items = []data.OrderItem{}
	}

	for i, item := range order.Items {
		OrderItem(&item)
		order.Price.Net += item.Price.Net
		order.Price.Gross += item.Price.Gross
		order.Items[i] = item
	}

}
Ejemplo n.º 9
0
func TestForestUpdateOrderInvalidStateTransition(t *testing.T) {

	invalidTransitions := [][2]string{
		// [2]string{data.OrderStateDraft, data.OrderStatePlaced},    // valid
		// [2]string{data.OrderStateDraft, data.OrderStateCancelled}, // valid
		[2]string{data.OrderStatePlaced, data.OrderStateDraft},
		[2]string{data.OrderStatePlaced, data.OrderStateCancelled},
		[2]string{data.OrderStateCancelled, data.OrderStateDraft},
		[2]string{data.OrderStateCancelled, data.OrderStatePlaced},
		[2]string{data.OrderStateDraft, "UNKNOWN"},
		[2]string{data.OrderStatePlaced, "UNKNOWN"},
		[2]string{data.OrderStateCancelled, "UNKNOWN"},
	}

	product := data.Product{
		Name: generateName("Product"),
		Price: data.Price{
			Vat: 20,
			Net: 100,
		},
	}

	createProduct(&product)

	for _, invalidTransition := range invalidTransitions {

		fromState, toState := invalidTransition[0], invalidTransition[1]

		order := data.Order{
			Items: []data.OrderItem{
				data.OrderItem{
					Product:  product,
					Quantity: 1,
				},
			},
		}

		createOrder(&order)

		if fromState != order.State {
			order.State = fromState
			updateOrder(&order)
		}

		payload := data.Order{
			State: toState,
		}

		got := Error{}

		r := getForestClient().PUT(t, forest.Path("/orders/{id}", order.ID).Content(payload, MimeJSON))

		// TODO:
		// forest.ExpectStatus(t, r, http.StatusBadRequest)
		forest.ExpectStatus(t, r, http.StatusInternalServerError)

		forest.ExpectJSONDocument(t, r, &got)

		if got.Message == "" {
			t.Error("Got empty error message")
		}

	}

}
Ejemplo n.º 10
0
func (tx *Tx) LoadOrder(order *data.Order) error {
	var err error

	err = tx.tx.QueryRow(
		`
			SELECT state, time FROM orders
			WHERE id = $1
		`,
		order.ID,
	).Scan(
		&order.State,
		&order.Time,
	)
	if err != nil {
		return err
	}
	// end SELECT FROM orders

	// reset item list:
	order.Items = nil

	rows, err := tx.tx.Query(
		`
			SELECT
				products.id,
				products.name,
				products.price_vat,
				products.price_net,
				order_items.quantity
			FROM order_items
			JOIN products ON products.id = order_items.product_id
			WHERE order_items.order_id = $1
		`,
		order.ID,
	)
	if err != nil {
		return err
	}
	// end SELECT FROM order_items JOIN products

	for rows.Next() {

		item := data.OrderItem{}

		err := rows.Scan(
			&item.Product.ID,
			&item.Product.Name,
			&item.Product.Price.Vat,
			&item.Product.Price.Net,
			&item.Quantity,
		)
		if err != nil {
			return err
		}

		order.Items = append(order.Items, item)

	} // end for rows

	return nil
}
Ejemplo n.º 11
0
func (tx *Tx) UpdateOrder(order *data.Order) error {

	err := tx.tx.QueryRow(
		`
			UPDATE orders
			SET state = $2, time = $3
			WHERE id = $1
			RETURNING id
		`,
		order.ID,
		order.State,
		order.Time,
	).Scan(
		&order.ID,
	)
	if err != nil {
		return err
	}
	// end UPDATE orders

	// reset items list (if method got well-populated order);
	// TODO: probably, update order items as well (if len > 0)?
	order.Items = nil

	rows, err := tx.tx.Query(
		`
			SELECT
				products.id,
				products.name,
				products.price_vat,
				products.price_net,
				order_items.quantity
			FROM order_items
			JOIN products ON products.id = order_items.product_id
			WHERE order_items.order_id = $1
		`,
		order.ID,
	)
	if err != nil {
		return err
	}
	// end SELECT FROM order_items JOIN products

	for rows.Next() {

		item := data.OrderItem{}

		err := rows.Scan(
			&item.Product.ID,
			&item.Product.Name,
			&item.Product.Price.Vat,
			&item.Product.Price.Net,
			&item.Quantity,
		)
		if err != nil {
			return err
		}

		order.Items = append(order.Items, item)

	} // end for rows

	return nil
}