|
@@ -0,0 +1,261 @@
|
|
|
+package provider
|
|
|
+
|
|
|
+import (
|
|
|
+ "context"
|
|
|
+ "fmt"
|
|
|
+ "strconv"
|
|
|
+ "time"
|
|
|
+
|
|
|
+ "github.com/hashicorp-demoapp/hashicups-client-go"
|
|
|
+ "github.com/hashicorp/terraform-plugin-framework/resource"
|
|
|
+ "github.com/hashicorp/terraform-plugin-framework/resource/schema"
|
|
|
+ "github.com/hashicorp/terraform-plugin-framework/types"
|
|
|
+)
|
|
|
+
|
|
|
+
|
|
|
+var (
|
|
|
+ _ resource.Resource = &orderResource{}
|
|
|
+ _ resource.ResourceWithConfigure = &orderResource{}
|
|
|
+)
|
|
|
+
|
|
|
+
|
|
|
+func NewOrderResource() resource.Resource {
|
|
|
+ return &orderResource{}
|
|
|
+}
|
|
|
+
|
|
|
+type orderResource struct {
|
|
|
+ client *hashicups.Client
|
|
|
+}
|
|
|
+
|
|
|
+func (r *orderResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
|
|
|
+
|
|
|
+
|
|
|
+ if req.ProviderData == nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ client, ok := req.ProviderData.(*hashicups.Client)
|
|
|
+ if !ok {
|
|
|
+ resp.Diagnostics.AddError("Unexpected Resource Configure Type",
|
|
|
+ fmt.Sprintf("Expected *hashicups.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData))
|
|
|
+ return
|
|
|
+ }
|
|
|
+ r.client = client
|
|
|
+}
|
|
|
+
|
|
|
+func (r *orderResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
|
|
|
+ resp.TypeName = req.ProviderTypeName + "_order"
|
|
|
+}
|
|
|
+
|
|
|
+func (r *orderResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
|
|
|
+ resp.Schema = schema.Schema{
|
|
|
+ Attributes: map[string]schema.Attribute{
|
|
|
+ "id": schema.StringAttribute{
|
|
|
+ Computed: true,
|
|
|
+ },
|
|
|
+ "last_updated": schema.StringAttribute{
|
|
|
+ Computed: true,
|
|
|
+ },
|
|
|
+ "items": schema.ListNestedAttribute{
|
|
|
+ Required: true,
|
|
|
+ NestedObject: schema.NestedAttributeObject{
|
|
|
+ Attributes: map[string]schema.Attribute{
|
|
|
+ "quantity": schema.Int64Attribute{
|
|
|
+ Required: true,
|
|
|
+ },
|
|
|
+ "coffee": schema.SingleNestedAttribute{
|
|
|
+ Required: true,
|
|
|
+ Attributes: map[string]schema.Attribute{
|
|
|
+ "id": schema.Int64Attribute{
|
|
|
+ Required: true,
|
|
|
+ },
|
|
|
+ "name": schema.StringAttribute{
|
|
|
+ Computed: true,
|
|
|
+ },
|
|
|
+ "teaser": schema.StringAttribute{
|
|
|
+ Computed: true,
|
|
|
+ },
|
|
|
+ "description": schema.StringAttribute{
|
|
|
+ Computed: true,
|
|
|
+ },
|
|
|
+ "price": schema.Float64Attribute{
|
|
|
+ Computed: true,
|
|
|
+ },
|
|
|
+ "image": schema.StringAttribute{
|
|
|
+ Computed: true,
|
|
|
+ },
|
|
|
+ },
|
|
|
+ },
|
|
|
+ },
|
|
|
+ },
|
|
|
+ },
|
|
|
+ },
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func (r *orderResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
|
|
|
+ var plan orderResourceModel
|
|
|
+
|
|
|
+
|
|
|
+ if r.client == nil {
|
|
|
+ resp.Diagnostics.AddError(
|
|
|
+ "cannot create order",
|
|
|
+ "client is not configured in orderResource.Create",
|
|
|
+ )
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ diags := req.Plan.Get(ctx, &plan)
|
|
|
+ resp.Diagnostics.Append(diags...)
|
|
|
+ if resp.Diagnostics.HasError() {
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ var items []hashicups.OrderItem
|
|
|
+ for _, item := range plan.Items {
|
|
|
+ items = append(items, hashicups.OrderItem{
|
|
|
+ Coffee: hashicups.Coffee{
|
|
|
+ ID: int(item.Coffee.ID.ValueInt64()),
|
|
|
+ },
|
|
|
+ Quantity: int(item.Quantity.ValueInt64()),
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ order, err := r.client.CreateOrder(items)
|
|
|
+ if err != nil {
|
|
|
+ resp.Diagnostics.AddError(
|
|
|
+ "Error creating order",
|
|
|
+ err.Error(),
|
|
|
+ )
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ plan.ID = types.StringValue(strconv.Itoa(order.ID))
|
|
|
+ for orderItemIndex, orderItem := range order.Items {
|
|
|
+ plan.Items[orderItemIndex] = orderItemModel{
|
|
|
+ Coffee: orderItemCoffeeModel{
|
|
|
+ ID: types.Int64Value(int64(orderItem.Coffee.ID)),
|
|
|
+ Name: types.StringValue(orderItem.Coffee.Name),
|
|
|
+ Teaser: types.StringValue(orderItem.Coffee.Teaser),
|
|
|
+ Description: types.StringValue(orderItem.Coffee.Description),
|
|
|
+ Price: types.Float64Value(orderItem.Coffee.Price),
|
|
|
+ Image: types.StringValue(orderItem.Coffee.Image),
|
|
|
+ },
|
|
|
+ Quantity: types.Int64Value(int64(orderItem.Quantity)),
|
|
|
+ }
|
|
|
+ }
|
|
|
+ plan.LastUpdated = types.StringValue(time.Now().Format(time.RFC850))
|
|
|
+
|
|
|
+
|
|
|
+ diags = resp.State.Set(ctx, plan)
|
|
|
+ resp.Diagnostics.Append(diags...)
|
|
|
+
|
|
|
+
|
|
|
+ if resp.Diagnostics.HasError() {
|
|
|
+ return
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func (r *orderResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
|
|
|
+ var state orderResourceModel
|
|
|
+
|
|
|
+
|
|
|
+ if r.client == nil {
|
|
|
+ resp.Diagnostics.AddError(
|
|
|
+ "cannot read order",
|
|
|
+ "client is not configured in orderResource.Read",
|
|
|
+ )
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ diags := req.State.Get(ctx, &state)
|
|
|
+ resp.Diagnostics.Append(diags...)
|
|
|
+ if resp.Diagnostics.HasError() {
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ id := state.ID.ValueString()
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ order, err := r.client.GetOrder(id)
|
|
|
+ if err != nil {
|
|
|
+ resp.Diagnostics.AddError(
|
|
|
+ "Error reading HashiCups order",
|
|
|
+ "Could not read HashiCups order "+state.ID.ValueString()+": "+err.Error(),
|
|
|
+ )
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ state.Items = []orderItemModel{}
|
|
|
+ for _, item := range order.Items {
|
|
|
+ itemState := orderItemModel{
|
|
|
+ Coffee: orderItemCoffeeModel{
|
|
|
+ ID: types.Int64Value(int64(item.Coffee.ID)),
|
|
|
+ Name: types.StringValue(item.Coffee.Name),
|
|
|
+ Teaser: types.StringValue(item.Coffee.Teaser),
|
|
|
+ Description: types.StringValue(item.Coffee.Description),
|
|
|
+ Price: types.Float64Value(item.Coffee.Price),
|
|
|
+ Image: types.StringValue(item.Coffee.Image),
|
|
|
+ },
|
|
|
+ Quantity: types.Int64Value(int64(item.Quantity)),
|
|
|
+ }
|
|
|
+ state.Items = append(state.Items, itemState)
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ diags = resp.State.Set(ctx, state)
|
|
|
+ resp.Diagnostics.Append(diags...)
|
|
|
+
|
|
|
+
|
|
|
+ if resp.Diagnostics.HasError() {
|
|
|
+ return
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func (r *orderResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+func (r *orderResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+type orderResourceModel struct {
|
|
|
+ ID types.String `tfsdk:"id"`
|
|
|
+ Items []orderItemModel `tfsdk:"items"`
|
|
|
+ LastUpdated types.String `tfsdk:"last_updated"`
|
|
|
+}
|
|
|
+
|
|
|
+type orderItemModel struct {
|
|
|
+ Quantity types.Int64 `tfsdk:"quantity"`
|
|
|
+ Coffee orderItemCoffeeModel `tfsdk:"coffee"`
|
|
|
+}
|
|
|
+
|
|
|
+type orderItemCoffeeModel struct {
|
|
|
+ ID types.Int64 `tfsdk:"id"`
|
|
|
+ Name types.String `tfsdk:"name"`
|
|
|
+ Teaser types.String `tfsdk:"teaser"`
|
|
|
+ Description types.String `tfsdk:"description"`
|
|
|
+ Price types.Float64 `tfsdk:"price"`
|
|
|
+ Image types.String `tfsdk:"image"`
|
|
|
+}
|