add sets up
This commit is contained in:
parent
8d5ba6a5e4
commit
c9ee2a1d24
@ -293,12 +293,13 @@ func (r *Request) DraftOrder(scheduler *workflow_execution.WorkflowSchedule) (*o
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *Request) PaymentTunnel(o *order.Order, scheduler *workflow_execution.WorkflowSchedule) error {
|
func (r *Request) PaymentTunnel(o *order.Order, scheduler *workflow_execution.WorkflowSchedule) error {
|
||||||
return o.Pay(scheduler, &tools.APIRequest{
|
/*return o.Pay(scheduler, &tools.APIRequest{
|
||||||
Caller: r.caller,
|
Caller: r.caller,
|
||||||
Username: r.user,
|
Username: r.user,
|
||||||
PeerID: r.peerID,
|
PeerID: r.peerID,
|
||||||
Groups: r.groups,
|
Groups: r.groups,
|
||||||
})
|
})*/
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1,25 +1,338 @@
|
|||||||
package bill
|
package bill
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"cloud.o-forge.io/core/oc-lib/dbs"
|
||||||
|
"cloud.o-forge.io/core/oc-lib/models/booking"
|
||||||
|
"cloud.o-forge.io/core/oc-lib/models/common/enum"
|
||||||
|
"cloud.o-forge.io/core/oc-lib/models/common/pricing"
|
||||||
|
"cloud.o-forge.io/core/oc-lib/models/peer"
|
||||||
|
"cloud.o-forge.io/core/oc-lib/models/resources/purchase_resource"
|
||||||
"cloud.o-forge.io/core/oc-lib/models/utils"
|
"cloud.o-forge.io/core/oc-lib/models/utils"
|
||||||
|
"cloud.o-forge.io/core/oc-lib/models/workflow_execution"
|
||||||
"cloud.o-forge.io/core/oc-lib/tools"
|
"cloud.o-forge.io/core/oc-lib/tools"
|
||||||
)
|
)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Bill is a struct that represents when emit billing
|
* Booking is a struct that represents a booking
|
||||||
*/
|
*/
|
||||||
|
|
||||||
type Bill struct {
|
type Bill struct {
|
||||||
utils.AbstractObject
|
utils.AbstractObject
|
||||||
|
OrderID string `json:"order_id" bson:"order_id" validate:"required"`
|
||||||
|
OrderBy string `json:"order_by" bson:"order_by" validate:"required"`
|
||||||
|
WorkflowID string `json:"workflow_id" bson:"workflow_id" validate:"required"`
|
||||||
|
WorkflowExecutionIDs []string `json:"workflow_execution_ids" bson:"workflow_execution_ids" validate:"required"`
|
||||||
|
Status enum.CompletionStatus `json:"status" bson:"status" default:"0"`
|
||||||
|
SubOrders map[string]*PeerOrder `json:"sub_orders" bson:"sub_orders"`
|
||||||
|
Total float64 `json:"total" bson:"total" validate:"required"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Bill) StoreDraftDefault() {
|
func (r *Bill) StoreDraftDefault() {
|
||||||
r.IsDraft = true
|
r.IsDraft = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *Bill) CanUpdate(set utils.DBObject) (bool, utils.DBObject) {
|
||||||
|
if !r.IsDraft && r.Status != set.(*Bill).Status {
|
||||||
|
return true, &Bill{Status: set.(*Bill).Status} // only state can be updated
|
||||||
|
}
|
||||||
|
return r.IsDraft, set
|
||||||
|
}
|
||||||
|
|
||||||
func (r *Bill) CanDelete() bool {
|
func (r *Bill) CanDelete() bool {
|
||||||
return r.IsDraft // only draft ComputeUnits can be deleted
|
return r.IsDraft // only draft order can be deleted
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Bill) DraftOrder(scheduler *workflow_execution.WorkflowSchedule, request *tools.APIRequest) error {
|
||||||
|
// set the draft order from the model
|
||||||
|
if err := o.draftStoreFromModel(scheduler, request); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Bill) Pay(scheduler *workflow_execution.WorkflowSchedule, request *tools.APIRequest) error {
|
||||||
|
if _, err := o.draftBookOrder(scheduler, request); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
o.Status = enum.PENDING
|
||||||
|
_, code, err := o.GetAccessor(request).UpdateOne(o, o.GetID())
|
||||||
|
if code != 200 || err != nil {
|
||||||
|
return errors.New("could not update the order" + fmt.Sprintf("%v", err))
|
||||||
|
}
|
||||||
|
if err := o.pay(request); err != nil { // pay the order
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
o.IsDraft = false
|
||||||
|
}
|
||||||
|
for _, exec := range scheduler.WorkflowExecution {
|
||||||
|
exec.IsDraft = false
|
||||||
|
_, code, err := utils.GenericUpdateOne(exec, exec.GetID(),
|
||||||
|
workflow_execution.NewAccessor(request), &workflow_execution.WorkflowExecution{})
|
||||||
|
if code != 200 || err != nil {
|
||||||
|
return errors.New("could not update the workflow execution" + fmt.Sprintf("%v", err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_, code, err = o.GetAccessor(request).UpdateOne(o, o.GetID())
|
||||||
|
if code != 200 || err != nil {
|
||||||
|
return errors.New("could not update the order" + fmt.Sprintf("%v", err))
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
TODO : TEMPORARY SET BOOKINGS TO UNDRAFT TO AVOID DELETION
|
||||||
|
BUT NEXT ONLY WHO IS PAYED WILL BE ALLOWED TO CHANGE IT
|
||||||
|
*/
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Bill) draftStoreFromModel(scheduler *workflow_execution.WorkflowSchedule, request *tools.APIRequest) error {
|
||||||
|
if request == nil {
|
||||||
|
return errors.New("no request found")
|
||||||
|
}
|
||||||
|
fmt.Println("Drafting order", scheduler.Workflow)
|
||||||
|
if scheduler.Workflow == nil || scheduler.Workflow.Graph == nil { // if the workflow has no graph, return an error
|
||||||
|
return errors.New("no graph found")
|
||||||
|
}
|
||||||
|
o.SetName()
|
||||||
|
o.WorkflowID = scheduler.Workflow.GetID()
|
||||||
|
o.IsDraft = true
|
||||||
|
o.OrderBy = request.PeerID
|
||||||
|
o.WorkflowExecutionIDs = []string{} // create an array of ids
|
||||||
|
for _, exec := range scheduler.WorkflowExecution {
|
||||||
|
o.WorkflowExecutionIDs = append(o.WorkflowExecutionIDs, exec.GetID())
|
||||||
|
}
|
||||||
|
// set the name of the order
|
||||||
|
resourcesByPeer := map[string][]pricing.PricedItemITF{} // create a map of resources by peer
|
||||||
|
|
||||||
|
processings := scheduler.Workflow.GetPricedItem(scheduler.Workflow.Graph.IsProcessing, request,
|
||||||
|
int(scheduler.SelectedBuyingStrategy), scheduler.SelectedPricingStrategy) // get the processing items
|
||||||
|
datas := scheduler.Workflow.GetPricedItem(scheduler.Workflow.Graph.IsData, request,
|
||||||
|
int(scheduler.SelectedBuyingStrategy), scheduler.SelectedPricingStrategy) // get the data items
|
||||||
|
storages := scheduler.Workflow.GetPricedItem(scheduler.Workflow.Graph.IsStorage, request,
|
||||||
|
int(scheduler.SelectedBuyingStrategy), scheduler.SelectedPricingStrategy) // get the storage items
|
||||||
|
workflows := scheduler.Workflow.GetPricedItem(scheduler.Workflow.Graph.IsWorkflow, request,
|
||||||
|
int(scheduler.SelectedBuyingStrategy), scheduler.SelectedPricingStrategy) // get the workflow items
|
||||||
|
for _, items := range []map[string]pricing.PricedItemITF{processings, datas, storages, workflows} {
|
||||||
|
for _, item := range items {
|
||||||
|
if _, ok := resourcesByPeer[item.GetCreatorID()]; !ok {
|
||||||
|
resourcesByPeer[item.GetCreatorID()] = []pricing.PricedItemITF{}
|
||||||
|
}
|
||||||
|
resourcesByPeer[item.GetCreatorID()] = append(resourcesByPeer[item.GetCreatorID()], item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for peerID, resources := range resourcesByPeer {
|
||||||
|
peerOrder := &PeerOrder{
|
||||||
|
Status: enum.DRAFTED,
|
||||||
|
PeerID: peerID,
|
||||||
|
}
|
||||||
|
peerOrder.GenerateID()
|
||||||
|
for _, resource := range resources {
|
||||||
|
peerOrder.AddItem(resource, len(resources)) // TODO SPECIALS REF ADDITIONALS NOTES
|
||||||
|
}
|
||||||
|
if o.SubOrders == nil {
|
||||||
|
o.SubOrders = map[string]*PeerOrder{}
|
||||||
|
}
|
||||||
|
o.SubOrders[peerOrder.GetID()] = peerOrder
|
||||||
|
}
|
||||||
|
// search an order with same user name and same session id
|
||||||
|
err := o.SumUpBill(request)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// should store the order
|
||||||
|
res, code, err := o.GetAccessor(request).Search(&dbs.Filters{
|
||||||
|
And: map[string][]dbs.Filter{
|
||||||
|
"workflow_id": {{Operator: dbs.EQUAL.String(), Value: o.WorkflowID}},
|
||||||
|
"order_by": {{Operator: dbs.EQUAL.String(), Value: request.PeerID}},
|
||||||
|
},
|
||||||
|
}, "", o.IsDraft)
|
||||||
|
if code != 200 || err != nil {
|
||||||
|
return errors.New("could not search the order" + fmt.Sprintf("%v", err))
|
||||||
|
}
|
||||||
|
if len(res) > 0 {
|
||||||
|
_, code, err := utils.GenericUpdateOne(o, res[0].GetID(), o.GetAccessor(request), o)
|
||||||
|
if code != 200 || err != nil {
|
||||||
|
return errors.New("could not update the order" + fmt.Sprintf("%v", err))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_, code, err := utils.GenericStoreOne(o, o.GetAccessor(request))
|
||||||
|
if code != 200 || err != nil {
|
||||||
|
return errors.New("could not store the order" + fmt.Sprintf("%v", err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Bill) draftBookOrder(scheduler *workflow_execution.WorkflowSchedule, request *tools.APIRequest) ([]*booking.Booking, error) {
|
||||||
|
draftedBookings := []*booking.Booking{}
|
||||||
|
if request == nil {
|
||||||
|
return draftedBookings, errors.New("no request found")
|
||||||
|
}
|
||||||
|
for _, exec := range scheduler.WorkflowExecution {
|
||||||
|
_, priceds, _, err := scheduler.Workflow.Planify(exec.ExecDate, exec.EndDate, request,
|
||||||
|
int(scheduler.SelectedBuyingStrategy), scheduler.SelectedPricingStrategy)
|
||||||
|
if err != nil {
|
||||||
|
return draftedBookings, errors.New("could not planify the workflow" + fmt.Sprintf("%v", err))
|
||||||
|
}
|
||||||
|
bookings := exec.Book(scheduler.UUID, scheduler.Workflow.UUID, priceds)
|
||||||
|
for _, booking := range bookings {
|
||||||
|
_, err := (&peer.Peer{}).LaunchPeerExecution(booking.DestPeerID, "",
|
||||||
|
tools.BOOKING, tools.POST, booking.Serialize(booking), request.Caller)
|
||||||
|
if err != nil {
|
||||||
|
return draftedBookings, errors.New("could not launch the peer execution : " + fmt.Sprintf("%v", err))
|
||||||
|
}
|
||||||
|
draftedBookings = append(draftedBookings, booking)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return draftedBookings, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Bill) Quantity() int {
|
||||||
|
return len(o.WorkflowExecutionIDs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Bill) SetName() {
|
||||||
|
d.Name = d.UUID + "_order_" + "_" + time.Now().UTC().Format("2006-01-02T15:04:05")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Bill) GetAccessor(request *tools.APIRequest) utils.Accessor {
|
func (d *Bill) GetAccessor(request *tools.APIRequest) utils.Accessor {
|
||||||
return NewAccessor(request) // Create a new instance of the accessor
|
return NewAccessor(request) // Create a new instance of the accessor
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *Bill) SumUpBill(request *tools.APIRequest) error {
|
||||||
|
for _, b := range d.SubOrders {
|
||||||
|
err := b.SumUpBill(request)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
d.Total += b.Total
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// TO FINISH
|
||||||
|
func (d *Bill) pay(request *tools.APIRequest) error {
|
||||||
|
responses := make(chan *PeerOrder, len(d.SubOrders))
|
||||||
|
var wg *sync.WaitGroup
|
||||||
|
wg.Add(len(d.SubOrders))
|
||||||
|
for _, b := range d.SubOrders {
|
||||||
|
go b.Pay(request, responses, wg)
|
||||||
|
}
|
||||||
|
wg.Wait()
|
||||||
|
errs := ""
|
||||||
|
gotAnUnpaid := false
|
||||||
|
count := 0
|
||||||
|
for range responses {
|
||||||
|
res := <-responses
|
||||||
|
count++
|
||||||
|
if res != nil {
|
||||||
|
if res.Error != "" {
|
||||||
|
errs += res.Error
|
||||||
|
}
|
||||||
|
if res.Status != enum.PAID {
|
||||||
|
gotAnUnpaid = true
|
||||||
|
}
|
||||||
|
d.Status = enum.PARTIAL
|
||||||
|
d.SubOrders[res.GetID()] = res
|
||||||
|
if count == len(d.SubOrders) && !gotAnUnpaid {
|
||||||
|
d.Status = enum.PAID
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if errs != "" {
|
||||||
|
return errors.New(errs)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type PeerOrder struct {
|
||||||
|
utils.AbstractObject
|
||||||
|
Error string `json:"error,omitempty" bson:"error,omitempty"`
|
||||||
|
PeerID string `json:"peer_id,omitempty" bson:"peer_id,omitempty"`
|
||||||
|
Status enum.CompletionStatus `json:"status" bson:"status" default:"0"`
|
||||||
|
BillingAddress string `json:"billing_address,omitempty" bson:"billing_address,omitempty"`
|
||||||
|
Items []*PeerItemOrder `json:"items,omitempty" bson:"items,omitempty"`
|
||||||
|
Total float64 `json:"total,omitempty" bson:"total,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *PeerOrder) Pay(request *tools.APIRequest, response chan *PeerOrder, wg *sync.WaitGroup) {
|
||||||
|
d.Status = enum.PENDING
|
||||||
|
go func() {
|
||||||
|
// DO SOMETHING TO PAY ON BLOCKCHAIN OR WHATEVER ON RETURN UPDATE STATUS
|
||||||
|
d.Status = enum.PAID // TO REMOVE LATER IT'S A MOCK
|
||||||
|
if d.Status == enum.PAID {
|
||||||
|
for _, b := range d.Items {
|
||||||
|
if !b.Item.IsPurchasable() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
accessor := purchase_resource.NewAccessor(request)
|
||||||
|
accessor.StoreOne(&purchase_resource.PurchaseResource{
|
||||||
|
ResourceID: b.Item.GetID(),
|
||||||
|
ResourceType: b.Item.GetType(),
|
||||||
|
EndDate: b.Item.GetLocationEnd(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.Status != enum.PENDING {
|
||||||
|
response <- d
|
||||||
|
}
|
||||||
|
wg.Done()
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *PeerOrder) SumUpBill(request *tools.APIRequest) error {
|
||||||
|
for _, b := range d.Items {
|
||||||
|
tot, err := b.GetPrice(request) // missing something
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
d.Total += tot
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *PeerOrder) AddItem(item pricing.PricedItemITF, quantity int) {
|
||||||
|
d.Items = append(d.Items, &PeerItemOrder{
|
||||||
|
Quantity: quantity,
|
||||||
|
Item: item,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *PeerOrder) SetName() {
|
||||||
|
d.Name = d.UUID + "_order_" + d.PeerID + "_" + time.Now().UTC().Format("2006-01-02T15:04:05")
|
||||||
|
}
|
||||||
|
|
||||||
|
type PeerItemOrder struct {
|
||||||
|
Quantity int `json:"quantity,omitempty" bson:"quantity,omitempty"`
|
||||||
|
Purchase purchase_resource.PurchaseResource `json:"purchase,omitempty" bson:"purchase,omitempty"`
|
||||||
|
Item pricing.PricedItemITF `json:"item,omitempty" bson:"item,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *PeerItemOrder) GetPrice(request *tools.APIRequest) (float64, error) {
|
||||||
|
accessor := purchase_resource.NewAccessor(request)
|
||||||
|
search, code, _ := accessor.Search(&dbs.Filters{
|
||||||
|
And: map[string][]dbs.Filter{
|
||||||
|
"resource_id": {{Operator: dbs.EQUAL.String(), Value: d.Item.GetID()}},
|
||||||
|
},
|
||||||
|
}, "", d.Purchase.IsDraft)
|
||||||
|
if code == 200 && len(search) > 0 {
|
||||||
|
for _, s := range search {
|
||||||
|
if s.(*purchase_resource.PurchaseResource).EndDate == nil || time.Now().UTC().After(*s.(*purchase_resource.PurchaseResource).EndDate) {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p, err := d.Item.GetPrice()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return p * float64(d.Quantity), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// WTF HOW TO SELECT THE RIGHT PRICE ???
|
||||||
|
// SHOULD SET A BUYING STATUS WHEN PAYMENT IS VALIDATED
|
||||||
|
@ -1,19 +1,12 @@
|
|||||||
package order
|
package order
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"cloud.o-forge.io/core/oc-lib/dbs"
|
|
||||||
"cloud.o-forge.io/core/oc-lib/models/booking"
|
"cloud.o-forge.io/core/oc-lib/models/booking"
|
||||||
"cloud.o-forge.io/core/oc-lib/models/common/enum"
|
"cloud.o-forge.io/core/oc-lib/models/common/enum"
|
||||||
"cloud.o-forge.io/core/oc-lib/models/common/pricing"
|
|
||||||
"cloud.o-forge.io/core/oc-lib/models/peer"
|
|
||||||
"cloud.o-forge.io/core/oc-lib/models/resources/purchase_resource"
|
"cloud.o-forge.io/core/oc-lib/models/resources/purchase_resource"
|
||||||
"cloud.o-forge.io/core/oc-lib/models/utils"
|
"cloud.o-forge.io/core/oc-lib/models/utils"
|
||||||
"cloud.o-forge.io/core/oc-lib/models/workflow_execution"
|
|
||||||
"cloud.o-forge.io/core/oc-lib/tools"
|
"cloud.o-forge.io/core/oc-lib/tools"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -23,12 +16,12 @@ import (
|
|||||||
|
|
||||||
type Order struct {
|
type Order struct {
|
||||||
utils.AbstractObject
|
utils.AbstractObject
|
||||||
|
ExecutionsID string `json:"executions_id" bson:"executions_id" validate:"required"`
|
||||||
OrderBy string `json:"order_by" bson:"order_by" validate:"required"`
|
OrderBy string `json:"order_by" bson:"order_by" validate:"required"`
|
||||||
WorkflowID string `json:"workflow_id" bson:"workflow_id" validate:"required"`
|
WorkflowID string `json:"workflow_id" bson:"workflow_id" validate:"required"`
|
||||||
WorkflowExecutionIDs []string `json:"workflow_execution_ids" bson:"workflow_execution_ids" validate:"required"`
|
Purchases []purchase_resource.PurchaseResource `json:"purchases" bson:"purchases"`
|
||||||
|
Bookings []booking.Booking `json:"bookings" bson:"bookings"`
|
||||||
Status enum.CompletionStatus `json:"status" bson:"status" default:"0"`
|
Status enum.CompletionStatus `json:"status" bson:"status" default:"0"`
|
||||||
SubOrders map[string]*PeerOrder `json:"sub_orders" bson:"sub_orders"`
|
|
||||||
Total float64 `json:"total" bson:"total" validate:"required"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Order) StoreDraftDefault() {
|
func (r *Order) StoreDraftDefault() {
|
||||||
@ -46,151 +39,8 @@ func (r *Order) CanDelete() bool {
|
|||||||
return r.IsDraft // only draft order can be deleted
|
return r.IsDraft // only draft order can be deleted
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *Order) DraftOrder(scheduler *workflow_execution.WorkflowSchedule, request *tools.APIRequest) error {
|
|
||||||
// set the draft order from the model
|
|
||||||
if err := o.draftStoreFromModel(scheduler, request); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *Order) Pay(scheduler *workflow_execution.WorkflowSchedule, request *tools.APIRequest) error {
|
|
||||||
if _, err := o.draftBookOrder(scheduler, request); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
o.Status = enum.PENDING
|
|
||||||
_, code, err := o.GetAccessor(request).UpdateOne(o, o.GetID())
|
|
||||||
if code != 200 || err != nil {
|
|
||||||
return errors.New("could not update the order" + fmt.Sprintf("%v", err))
|
|
||||||
}
|
|
||||||
if err := o.pay(request); err != nil { // pay the order
|
|
||||||
return err
|
|
||||||
} else {
|
|
||||||
o.IsDraft = false
|
|
||||||
}
|
|
||||||
for _, exec := range scheduler.WorkflowExecution {
|
|
||||||
exec.IsDraft = false
|
|
||||||
_, code, err := utils.GenericUpdateOne(exec, exec.GetID(),
|
|
||||||
workflow_execution.NewAccessor(request), &workflow_execution.WorkflowExecution{})
|
|
||||||
if code != 200 || err != nil {
|
|
||||||
return errors.New("could not update the workflow execution" + fmt.Sprintf("%v", err))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_, code, err = o.GetAccessor(request).UpdateOne(o, o.GetID())
|
|
||||||
if code != 200 || err != nil {
|
|
||||||
return errors.New("could not update the order" + fmt.Sprintf("%v", err))
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
TODO : TEMPORARY SET BOOKINGS TO UNDRAFT TO AVOID DELETION
|
|
||||||
BUT NEXT ONLY WHO IS PAYED WILL BE ALLOWED TO CHANGE IT
|
|
||||||
*/
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *Order) draftStoreFromModel(scheduler *workflow_execution.WorkflowSchedule, request *tools.APIRequest) error {
|
|
||||||
if request == nil {
|
|
||||||
return errors.New("no request found")
|
|
||||||
}
|
|
||||||
fmt.Println("Drafting order", scheduler.Workflow)
|
|
||||||
if scheduler.Workflow == nil || scheduler.Workflow.Graph == nil { // if the workflow has no graph, return an error
|
|
||||||
return errors.New("no graph found")
|
|
||||||
}
|
|
||||||
o.SetName()
|
|
||||||
o.WorkflowID = scheduler.Workflow.GetID()
|
|
||||||
o.IsDraft = true
|
|
||||||
o.OrderBy = request.PeerID
|
|
||||||
o.WorkflowExecutionIDs = []string{} // create an array of ids
|
|
||||||
for _, exec := range scheduler.WorkflowExecution {
|
|
||||||
o.WorkflowExecutionIDs = append(o.WorkflowExecutionIDs, exec.GetID())
|
|
||||||
}
|
|
||||||
// set the name of the order
|
|
||||||
resourcesByPeer := map[string][]pricing.PricedItemITF{} // create a map of resources by peer
|
|
||||||
|
|
||||||
processings := scheduler.Workflow.GetPricedItem(scheduler.Workflow.Graph.IsProcessing, request,
|
|
||||||
int(scheduler.SelectedBuyingStrategy), scheduler.SelectedPricingStrategy) // get the processing items
|
|
||||||
datas := scheduler.Workflow.GetPricedItem(scheduler.Workflow.Graph.IsData, request,
|
|
||||||
int(scheduler.SelectedBuyingStrategy), scheduler.SelectedPricingStrategy) // get the data items
|
|
||||||
storages := scheduler.Workflow.GetPricedItem(scheduler.Workflow.Graph.IsStorage, request,
|
|
||||||
int(scheduler.SelectedBuyingStrategy), scheduler.SelectedPricingStrategy) // get the storage items
|
|
||||||
workflows := scheduler.Workflow.GetPricedItem(scheduler.Workflow.Graph.IsWorkflow, request,
|
|
||||||
int(scheduler.SelectedBuyingStrategy), scheduler.SelectedPricingStrategy) // get the workflow items
|
|
||||||
for _, items := range []map[string]pricing.PricedItemITF{processings, datas, storages, workflows} {
|
|
||||||
for _, item := range items {
|
|
||||||
if _, ok := resourcesByPeer[item.GetCreatorID()]; !ok {
|
|
||||||
resourcesByPeer[item.GetCreatorID()] = []pricing.PricedItemITF{}
|
|
||||||
}
|
|
||||||
resourcesByPeer[item.GetCreatorID()] = append(resourcesByPeer[item.GetCreatorID()], item)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for peerID, resources := range resourcesByPeer {
|
|
||||||
peerOrder := &PeerOrder{
|
|
||||||
Status: enum.DRAFTED,
|
|
||||||
PeerID: peerID,
|
|
||||||
}
|
|
||||||
peerOrder.GenerateID()
|
|
||||||
for _, resource := range resources {
|
|
||||||
peerOrder.AddItem(resource, len(resources)) // TODO SPECIALS REF ADDITIONALS NOTES
|
|
||||||
}
|
|
||||||
if o.SubOrders == nil {
|
|
||||||
o.SubOrders = map[string]*PeerOrder{}
|
|
||||||
}
|
|
||||||
o.SubOrders[peerOrder.GetID()] = peerOrder
|
|
||||||
}
|
|
||||||
// search an order with same user name and same session id
|
|
||||||
err := o.SumUpBill(request)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
// should store the order
|
|
||||||
res, code, err := o.GetAccessor(request).Search(&dbs.Filters{
|
|
||||||
And: map[string][]dbs.Filter{
|
|
||||||
"workflow_id": {{Operator: dbs.EQUAL.String(), Value: o.WorkflowID}},
|
|
||||||
"order_by": {{Operator: dbs.EQUAL.String(), Value: request.PeerID}},
|
|
||||||
},
|
|
||||||
}, "", o.IsDraft)
|
|
||||||
if code != 200 || err != nil {
|
|
||||||
return errors.New("could not search the order" + fmt.Sprintf("%v", err))
|
|
||||||
}
|
|
||||||
if len(res) > 0 {
|
|
||||||
_, code, err := utils.GenericUpdateOne(o, res[0].GetID(), o.GetAccessor(request), o)
|
|
||||||
if code != 200 || err != nil {
|
|
||||||
return errors.New("could not update the order" + fmt.Sprintf("%v", err))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
_, code, err := utils.GenericStoreOne(o, o.GetAccessor(request))
|
|
||||||
if code != 200 || err != nil {
|
|
||||||
return errors.New("could not store the order" + fmt.Sprintf("%v", err))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *Order) draftBookOrder(scheduler *workflow_execution.WorkflowSchedule, request *tools.APIRequest) ([]*booking.Booking, error) {
|
|
||||||
draftedBookings := []*booking.Booking{}
|
|
||||||
if request == nil {
|
|
||||||
return draftedBookings, errors.New("no request found")
|
|
||||||
}
|
|
||||||
for _, exec := range scheduler.WorkflowExecution {
|
|
||||||
_, priceds, _, err := scheduler.Workflow.Planify(exec.ExecDate, exec.EndDate, request,
|
|
||||||
int(scheduler.SelectedBuyingStrategy), scheduler.SelectedPricingStrategy)
|
|
||||||
if err != nil {
|
|
||||||
return draftedBookings, errors.New("could not planify the workflow" + fmt.Sprintf("%v", err))
|
|
||||||
}
|
|
||||||
bookings := exec.Book(scheduler.UUID, scheduler.Workflow.UUID, priceds)
|
|
||||||
for _, booking := range bookings {
|
|
||||||
_, err := (&peer.Peer{}).LaunchPeerExecution(booking.DestPeerID, "",
|
|
||||||
tools.BOOKING, tools.POST, booking.Serialize(booking), request.Caller)
|
|
||||||
if err != nil {
|
|
||||||
return draftedBookings, errors.New("could not launch the peer execution : " + fmt.Sprintf("%v", err))
|
|
||||||
}
|
|
||||||
draftedBookings = append(draftedBookings, booking)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return draftedBookings, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *Order) Quantity() int {
|
func (o *Order) Quantity() int {
|
||||||
return len(o.WorkflowExecutionIDs)
|
return len(o.Purchases) + len(o.Purchases)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Order) SetName() {
|
func (d *Order) SetName() {
|
||||||
@ -200,138 +50,3 @@ func (d *Order) SetName() {
|
|||||||
func (d *Order) GetAccessor(request *tools.APIRequest) utils.Accessor {
|
func (d *Order) GetAccessor(request *tools.APIRequest) utils.Accessor {
|
||||||
return NewAccessor(request) // Create a new instance of the accessor
|
return NewAccessor(request) // Create a new instance of the accessor
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Order) SumUpBill(request *tools.APIRequest) error {
|
|
||||||
for _, b := range d.SubOrders {
|
|
||||||
err := b.SumUpBill(request)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
d.Total += b.Total
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// TO FINISH
|
|
||||||
func (d *Order) pay(request *tools.APIRequest) error {
|
|
||||||
responses := make(chan *PeerOrder, len(d.SubOrders))
|
|
||||||
var wg *sync.WaitGroup
|
|
||||||
wg.Add(len(d.SubOrders))
|
|
||||||
for _, b := range d.SubOrders {
|
|
||||||
go b.Pay(request, responses, wg)
|
|
||||||
}
|
|
||||||
wg.Wait()
|
|
||||||
errs := ""
|
|
||||||
gotAnUnpaid := false
|
|
||||||
count := 0
|
|
||||||
for range responses {
|
|
||||||
res := <-responses
|
|
||||||
count++
|
|
||||||
if res != nil {
|
|
||||||
if res.Error != "" {
|
|
||||||
errs += res.Error
|
|
||||||
}
|
|
||||||
if res.Status != enum.PAID {
|
|
||||||
gotAnUnpaid = true
|
|
||||||
}
|
|
||||||
d.Status = enum.PARTIAL
|
|
||||||
d.SubOrders[res.GetID()] = res
|
|
||||||
if count == len(d.SubOrders) && !gotAnUnpaid {
|
|
||||||
d.Status = enum.PAID
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if errs != "" {
|
|
||||||
return errors.New(errs)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type PeerOrder struct {
|
|
||||||
utils.AbstractObject
|
|
||||||
Error string `json:"error,omitempty" bson:"error,omitempty"`
|
|
||||||
PeerID string `json:"peer_id,omitempty" bson:"peer_id,omitempty"`
|
|
||||||
Status enum.CompletionStatus `json:"status" bson:"status" default:"0"`
|
|
||||||
BillingAddress string `json:"billing_address,omitempty" bson:"billing_address,omitempty"`
|
|
||||||
Items []*PeerItemOrder `json:"items,omitempty" bson:"items,omitempty"`
|
|
||||||
Total float64 `json:"total,omitempty" bson:"total,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *PeerOrder) Pay(request *tools.APIRequest, response chan *PeerOrder, wg *sync.WaitGroup) {
|
|
||||||
d.Status = enum.PENDING
|
|
||||||
go func() {
|
|
||||||
// DO SOMETHING TO PAY ON BLOCKCHAIN OR WHATEVER ON RETURN UPDATE STATUS
|
|
||||||
d.Status = enum.PAID // TO REMOVE LATER IT'S A MOCK
|
|
||||||
if d.Status == enum.PAID {
|
|
||||||
for _, b := range d.Items {
|
|
||||||
if !b.Item.IsPurchasable() {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
accessor := purchase_resource.NewAccessor(request)
|
|
||||||
accessor.StoreOne(&purchase_resource.PurchaseResource{
|
|
||||||
ResourceID: b.Item.GetID(),
|
|
||||||
ResourceType: b.Item.GetType(),
|
|
||||||
EndDate: b.Item.GetLocationEnd(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if d.Status != enum.PENDING {
|
|
||||||
response <- d
|
|
||||||
}
|
|
||||||
wg.Done()
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *PeerOrder) SumUpBill(request *tools.APIRequest) error {
|
|
||||||
for _, b := range d.Items {
|
|
||||||
tot, err := b.GetPrice(request) // missing something
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
d.Total += tot
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *PeerOrder) AddItem(item pricing.PricedItemITF, quantity int) {
|
|
||||||
d.Items = append(d.Items, &PeerItemOrder{
|
|
||||||
Quantity: quantity,
|
|
||||||
Item: item,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *PeerOrder) SetName() {
|
|
||||||
d.Name = d.UUID + "_order_" + d.PeerID + "_" + time.Now().UTC().Format("2006-01-02T15:04:05")
|
|
||||||
}
|
|
||||||
|
|
||||||
type PeerItemOrder struct {
|
|
||||||
Quantity int `json:"quantity,omitempty" bson:"quantity,omitempty"`
|
|
||||||
Purchase purchase_resource.PurchaseResource `json:"purchase,omitempty" bson:"purchase,omitempty"`
|
|
||||||
Item pricing.PricedItemITF `json:"item,omitempty" bson:"item,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *PeerItemOrder) GetPrice(request *tools.APIRequest) (float64, error) {
|
|
||||||
accessor := purchase_resource.NewAccessor(request)
|
|
||||||
search, code, _ := accessor.Search(&dbs.Filters{
|
|
||||||
And: map[string][]dbs.Filter{
|
|
||||||
"resource_id": {{Operator: dbs.EQUAL.String(), Value: d.Item.GetID()}},
|
|
||||||
},
|
|
||||||
}, "", d.Purchase.IsDraft)
|
|
||||||
if code == 200 && len(search) > 0 {
|
|
||||||
for _, s := range search {
|
|
||||||
if s.(*purchase_resource.PurchaseResource).EndDate == nil || time.Now().UTC().After(*s.(*purchase_resource.PurchaseResource).EndDate) {
|
|
||||||
return 0, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
p, err := d.Item.GetPrice()
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
return p * float64(d.Quantity), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// WTF HOW TO SELECT THE RIGHT PRICE ???
|
|
||||||
// SHOULD SET A BUYING STATUS WHEN PAYMENT IS VALIDATED
|
|
||||||
|
Loading…
Reference in New Issue
Block a user