Let the platform do the work

How to Manipulate Quotes

Overview

A PHP example demonstrating how to manipulate Quotes and related record data such as ProductBundles, Products, and ProductBundleNotes. 

Manipulating Quotes

Authenticating

First, you will need to authenticate to the Sugar API. An example is shown below:

  <?php

$instance_url = "http://{site_url}/rest/v11";
$username = "admin";
$password = "password";

//Login - POST /oauth2/token
$auth_url = $instance_url . "/oauth2/token";

$oauth2_token_arguments = array(
    "grant_type" => "password",
    //client id - default is sugar. 
    //It is recommended to create your own in Admin > OAuth Keys
    "client_id" => "sugar", 
    "client_secret" => "",
    "username" => $username,
    "password" => $password,
    //platform type - default is base.
    //It is recommend to change the platform to a custom name such as "custom_api" to avoid authentication conflicts.
    "platform" => "custom_api" 
);

$auth_request = curl_init($auth_url);
curl_setopt($auth_request, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
curl_setopt($auth_request, CURLOPT_HEADER, false);
curl_setopt($auth_request, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($auth_request, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($auth_request, CURLOPT_FOLLOWLOCATION, 0);
curl_setopt($auth_request, CURLOPT_HTTPHEADER, array(
    "Content-Type: application/json"
));

//convert arguments to json
$json_arguments = json_encode($oauth2_token_arguments);
curl_setopt($auth_request, CURLOPT_POSTFIELDS, $json_arguments);

//execute request
$oauth2_token_response = curl_exec($auth_request);

//decode oauth2 response to get token
$oauth2_token_response_obj = json_decode($oauth2_token_response);
$oauth_token = $oauth2_token_response_obj->access_token;

More information on authenticating can be found in the How to Authenticate and Log Out example and /oauth2/logout endpoint documentation.

Creating a Quote

Once authenticated, we can submit a Quote record using the <module> endpoint. Since a Quote record is a sum of its parts (i.e. ProductBundles and Products) you can submit the related ProductBundles and Products in the same request payload using the relationship Links and the "create" property.

  //Create Records - POST /<module>
$url = $instance_url . "/Quotes";
//Set up the Record details
$DateTime = new DateTime();
//Expected Close Date in 1 Month
$DateTime->add(new DateInterval("P1M"));
//Quote Record
$quote = array(
    'name' => 'Test Quote',
    'quote_stage' => 'Draft',
    'date_quote_expected_closed' => $DateTime->format(DateTime::ISO8601),
    //Create Product Bundles
    'product_bundles' => array(
        'create' => array(
            array(
                "name" => "Product Bundle 1",
                "bundle_stage" => "Draft",
                "currency_id" => ":-99",
                "base_rate" => "1.0",
                "shipping" => "0.00",
                "products" => array(
                    //Create Product in Bundle 1
                    "create" => array(
                        array(
                            "tax_class" => "Taxable",
                            "quantity" => 1000.00,
                            "name" => "Test Product 1",
                            "description" => "My Test Product",
                            "mft_part_num" => "mft100012021",
                            "cost_price" =>  "100.00",
                            "list_price" =>  "200.00",
                            "discount_price" =>  "175.00",
                            "discount_amount" =>  "0.00",
                            "discount_select" =>  0,
                            "product_template_id" =>  "",
                            "type_id"  =>  "",
                            "status"  =>  "Quotes"
                        )
                    )
                ),
                //Create Product Bundle Note in Bundle 1
                "product_bundle_notes" => array(
                    "create" => array(
                        array(
                            "description" => "Free shipping",
                            "position" => 1
                        )
                    )
                )
            ),
            array(
                "name" => "Product Bundle 2",
                "bundle_stage" => "Draft",
                "currency_id" => ":-99",
                "base_rate" => "1.0",
                "shipping" => "25.00",
                "products" => array(
                    //Create Products in Bundle 2
                    "create" => array(
                        array(
                            "quantity" => 1000.00,
                            "name" => "Test Product 2",
                            "description" => "My Other Product",
                            "mft_part_num" => "mft100012234",
                            "cost_price" =>  "150.00",
                            "list_price" =>  "300.00",
                            "discount_price" =>  "275.00",
                            "discount_amount" =>  "0.00",
                            "discount_select" =>  0,
                            "product_template_id" =>  "",
                            "type_id"  =>  "",
                            "status"  =>  "Quotes"
                        ),
                        array(
                            "quantity" => 500.00,
                            "name" => "Test Product 3",
                            "description" => "My Other Other Product",
                            "mft_part_num" => "mft100012123",
                            "cost_price" =>  "10.00",
                            "list_price" =>  "500.00",
                            "discount_price" =>  "400.00",
                            "discount_amount" =>  "0.00",
                            "discount_select" =>  0,
                            "product_template_id" =>  "",
                            "type_id"  =>  "",
                            "status"  =>  "Quotes"
                        )
                    )
                )
            )
        ),
    )
);

$curl_request = curl_init($url);
curl_setopt($curl_request, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
curl_setopt($curl_request, CURLOPT_HEADER, false);
curl_setopt($curl_request, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($curl_request, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl_request, CURLOPT_FOLLOWLOCATION, 0);
curl_setopt($curl_request, CURLOPT_HTTPHEADER, array(
    "Content-Type: application/json",
    "oauth-token: {$oauth_token}"
));

//convert arguments to json
$json_arguments = json_encode($quote);
curl_setopt($curl_request, CURLOPT_POSTFIELDS, $json_arguments);
//execute request
$curl_response = curl_exec($curl_request);
//decode json
$createdQuote = json_decode($curl_response);

//display the created record
print_r($createdQuote);
curl_close($curl_request);

Request Payload

The data sent to the server is shown below:

  {
  "name": "Test Quote",
  "quote_stage": "Draft",
  "date_quote_expected_closed": "2017-06-12T11:51:57-0400",
  "product_bundles": {
    "create": [
      {
        "name": "Product Bundle 1",
        "bundle_stage": "Draft",
        "currency_id": ":-99",
        "base_rate": "1.0",
        "shipping": "0.00",
        "products": {
          "create": [
            {
              "tax_class": "Taxable",
              "quantity": 1000,
              "name": "Test Product 1",
              "description": "My Test Product",
              "mft_part_num": "mft100012021",
              "cost_price": "100.00",
              "list_price": "200.00",
              "discount_price": "175.00",
              "discount_amount": "0.00",
              "discount_select": 0,
              "product_template_id": "",
              "type_id": "",
              "status": "Quotes"
            }
          ]
        },
        "product_bundle_notes": {
          "create": [
            {
              "description": "Free shipping",
              "position": 1
            }
          ]
        }
      },
      {
        "name": "Product Bundle 2",
        "bundle_stage": "Draft",
        "currency_id": ":-99",
        "base_rate": "1.0",
        "shipping": "25.00",
        "products": {
          "create": [
            {
              "quantity": 1000,
              "name": "Test Product 2",
              "description": "My Other Product",
              "mft_part_num": "mft100012234",
              "cost_price": "150.00",
              "list_price": "300.00",
              "discount_price": "275.00",
              "discount_amount": "0.00",
              "discount_select": 0,
              "product_template_id": "",
              "type_id": "",
              "status": "Quotes"
            },
            {
              "quantity": 500,
              "name": "Test Product 3",
              "description": "My Other Other Product",
              "mft_part_num": "mft100012123",
              "cost_price": "10.00",
              "list_price": "500.00",
              "discount_price": "400.00",
              "discount_amount": "0.00",
              "discount_select": 0,
              "product_template_id": "",
              "type_id": "",
              "status": "Quotes"
            }
          ]
        }
      }
    ]
  }
}

Response

The data received from the server is shown below:

  {
  "id": "ee1e1ae8-372a-11e7-8bf4-3c15c2c94fb0",
  "name": "Test Quote",
  "date_entered": "2017-05-12T11:51:57-04:00",
  "date_modified": "2017-05-12T11:51:57-04:00",
  "modified_user_id": "1",
  "modified_by_name": "Administrator",
  "modified_user_link": {
    "full_name": "Administrator",
    "id": "1",
    "_acl": {
      "fields": {
        "pwd_last_changed": {
          "write": "no",
          "create": "no"
        },
        "last_login": {
          "write": "no",
          "create": "no"
        }
      },
      "delete": "no",
      "_hash": "08b99a97c2e8d792f7a44d8882b5af6d"
    }
  },
  "created_by": "1",
  "created_by_name": "Administrator",
  "created_by_link": {
    "full_name": "Administrator",
    "id": "1",
    "_acl": {
      "fields": {
        "pwd_last_changed": {
          "write": "no",
          "create": "no"
        },
        "last_login": {
          "write": "no",
          "create": "no"
        }
      },
      "delete": "no",
      "_hash": "08b99a97c2e8d792f7a44d8882b5af6d"
    }
  },
  "description": "",
  "deleted": false,
  "shipper_id": "",
  "shipper_name": "",
  "shippers": {
    "name": "",
    "id": "",
    "_acl": {
      "fields": [

      ],
      "_hash": "654d337e0e912edaa00dbb0fb3dc3c17"
    }
  },
  "taxrate_id": "",
  "taxrate_name": "",
  "taxrates": {
    "name": "",
    "id": "",
    "_acl": {
      "fields": [

      ],
      "_hash": "654d337e0e912edaa00dbb0fb3dc3c17"
    }
  },
  "taxrate_value": "0.000000",
  "show_line_nums": true,
  "quote_type": "Quotes",
  "date_quote_expected_closed": "2017-06-12",
  "original_po_date": "",
  "payment_terms": "",
  "date_quote_closed": "",
  "date_order_shipped": "",
  "order_stage": "",
  "quote_stage": "Draft",
  "purchase_order_num": "",
  "quote_num": 2,
  "subtotal": "650000.000000",
  "subtotal_usdollar": "650000.000000",
  "shipping": "0.000000",
  "shipping_usdollar": "0.000000",
  "discount": "",
  "deal_tot": "0.00",
  "deal_tot_discount_percentage": "0.00",
  "deal_tot_usdollar": "0.00",
  "new_sub": "650000.000000",
  "new_sub_usdollar": "650000.000000",
  "taxable_subtotal": "650000.000000",
  "tax": "0.000000",
  "tax_usdollar": "0.000000",
  "total": "650000.000000",
  "total_usdollar": "650000.000000",
  "billing_address_street": "",
  "billing_address_city": "",
  "billing_address_state": "",
  "billing_address_postalcode": "",
  "billing_address_country": "",
  "shipping_address_street": "",
  "shipping_address_city": "",
  "shipping_address_state": "",
  "shipping_address_postalcode": "",
  "shipping_address_country": "",
  "system_id": 1,
  "shipping_account_name": "",
  "shipping_accounts": {
    "name": "",
    "id": "",
    "_acl": {
      "fields": [

      ],
      "_hash": "654d337e0e912edaa00dbb0fb3dc3c17"
    }
  },
  "shipping_account_id": "",
  "shipping_contact_name": "",
  "shipping_contacts": {
    "full_name": "",
    "id": "",
    "_acl": {
      "fields": [

      ],
      "_hash": "654d337e0e912edaa00dbb0fb3dc3c17"
    },
    "last_name": ""
  },
  "shipping_contact_id": "",
  "account_name": "",
  "billing_accounts": {
    "name": "",
    "id": "",
    "_acl": {
      "fields": [

      ],
      "_hash": "654d337e0e912edaa00dbb0fb3dc3c17"
    }
  },
  "account_id": "",
  "billing_account_name": "",
  "billing_account_id": "",
  "billing_contact_name": "",
  "billing_contacts": {
    "full_name": "",
    "id": "",
    "_acl": {
      "fields": [

      ],
      "_hash": "654d337e0e912edaa00dbb0fb3dc3c17"
    },
    "last_name": ""
  },
  "billing_contact_id": "",
  "opportunity_name": "",
  "opportunities": {
    "name": "",
    "id": "",
    "_acl": {
      "fields": [

      ],
      "_hash": "654d337e0e912edaa00dbb0fb3dc3c17"
    }
  },
  "opportunity_id": "",
  "following": "",
  "my_favorite": false,
  "tag": [

  ],
  "locked_fields": [

  ],
  "assigned_user_id": "",
  "assigned_user_name": "",
  "assigned_user_link": {
    "full_name": "",
    "id": "",
    "_acl": {
      "fields": [

      ],
      "_hash": "654d337e0e912edaa00dbb0fb3dc3c17"
    }
  },
  "team_count": "",
  "team_count_link": {
    "team_count": "",
    "id": "1",
    "_acl": {
      "fields": [

      ],
      "_hash": "654d337e0e912edaa00dbb0fb3dc3c17"
    }
  },
  "team_name": [
    {
      "id": "a0512788-3680-11e7-b42f-3c15c2c94fb0",
      "name": "Administrator",
      "name_2": "",
      "primary": false,
      "selected": false
    },
    {
      "id": "1",
      "name": "Global",
      "name_2": "",
      "primary": true,
      "selected": false
    }
  ],
  "currency_id": "-99",
  "base_rate": "1.000000",
  "currency_name": "",
  "currencies": {
    "name": "",
    "id": "-99",
    "_acl": {
      "fields": [

      ],
      "_hash": "654d337e0e912edaa00dbb0fb3dc3c17"
    },
    "symbol": ""
  },
  "currency_symbol": "",
  "_acl": {
    "fields": {

    }
  },
  "_module": "Quotes"
}

You might notice that the Response does not contain the related data. To view the related data use the <module>/<record_id>/link/<link_name> - GET Endpoint.

Modifying the Quote's Product Bundles

Once the quote is created, you might need to add or remove Product Bundles from the Quote. This can be done using the /<module>/<record> - PUT endpoint.

  //Create a new ProductBundle
$url = $instance_url . "/ProductBundles";
$productBundle = array(
        "name" => "Product Bundle 3",
        "bundle_stage" => "Draft",
        "currency_id" => ":-99",
        "base_rate" => "1.0",
        "shipping" => "0.00",
        "products" => array(
            //Create Product in Bundle 3
            "create" => array(
                array(
                    "tax_class" => "Taxable",
                    "quantity" => 100.00,
                    "name" => "Test Product 3",
                    "description" => "Test Product 3",
                    "mft_part_num" => "mft100012021",
                    "cost_price" =>  "100.00",
                    "list_price" =>  "250.00",
                    "discount_price" =>  "175.00",
                    "discount_amount" =>  "0.00",
                    "discount_select" =>  0,
                    "product_template_id" =>  "",
                    "type_id"  =>  "",
                    "status"  =>  "Quotes",
                    "position" => 0
                )
            )
        ),
        //Create Product Bundle Note in Bundle 3
        "product_bundle_notes" => array(
            "create" => array(
                array(
                    "description" => "Free shipping",
                    "position" => 1
                )
            )
        )
    );
$curl_request = curl_init($url);
curl_setopt($curl_request, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
curl_setopt($curl_request, CURLOPT_HEADER, false);
curl_setopt($curl_request, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($curl_request, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl_request, CURLOPT_FOLLOWLOCATION, 0);
curl_setopt($curl_request, CURLOPT_HTTPHEADER, array(
    "Content-Type: application/json",
    "oauth-token: {$oauth_token}"
));

//convert arguments to json
$json_arguments = json_encode($productBundle);
curl_setopt($curl_request, CURLOPT_POSTFIELDS, $json_arguments);
//execute request
$curl_response = curl_exec($curl_request);
//decode json
$createdBundle = json_decode($curl_response);

//display the created record
print_r($createdBundle);
curl_close($curl_request);

//Add Bundle to Previously Created Quote
//PUT to /Quotes/<record_id>
$url = $instance_url . "/Quotes/".$createdQuote->id;
$quote = array(
    'product_bundles' => array(
        'delete' => array(
            'some_bundle_id'
        ),
        'add' => array(
            $createdBundle->id
        )
    )
);

$curl_request = curl_init($url);
curl_setopt($curl_request, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
curl_setopt($curl_request, CURLOPT_HEADER, false);
curl_setopt($curl_request, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($curl_request, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl_request, CURLOPT_FOLLOWLOCATION, 0);
curl_setopt($curl_request, CURLOPT_HTTPHEADER, array(
    "Content-Type: application/json",
    "oauth-token: {$oauth_token}"
));

//convert arguments to json
$json_arguments = json_encode($quote);
curl_setopt($curl_request, CURLOPT_POSTFIELDS, $json_arguments);
//PUT Request
curl_setopt($curl_request, CURLOPT_CUSTOMREQUEST, "PUT");
//execute request
$curl_response = curl_exec($curl_request);
//decode json
$updatedQuote = json_decode($curl_response);

//display the updated quote record
print_r($updatedQuote);
curl_close($curl_request);

 The above script removes a previously related Product Bundle from the Quote and adds the Product Bundle that was created before it in the script.

Request Payload

The data sent to the server to alter the Quotes Product Bundles is shown below:

{
  "product_bundles": {
    "delete": [
      "some_bundle_id"
    ],
    "add": [
      "803972ea-3741-11e7-8edc-3c15c2c94fb0"
    ]
  }
}

Response Payload

The response payload will match the standard /<module>/<record> - PUT Endpoint Response which is the entire values of the updated record. The previous Response for Creating the quote is the same as shown above.

Download

You can download the full API example here.