Skip to main content

Quotation

Quotations are purchase offers that occur after a basket submission. The user wants to create a quotation from the products in their basket and can create a new quotation by giving a name.

If the division of the user is main-division then the initial status of quotation will be set to pending status. If the division of the user is sub-division the initial status of quotation depends on IS_SUB_DIVISION_QUOTATION_APPROVAL_REQUIRED dynamic setting. If it is true the status will be set to request approval, if it is false the status will be set to pending status. The default value of this setting is true.

There is a hierarchy regarding updating the quotation. You can understand this structure better in the attached image.

How to Manage Quotations?

There are 2 API services to manage quotations:

Via omnishop platform /api/v1/my-quotations/ endpoint to manage operations for users to their own quotations. Via omnitron admin users can use /api/v1/quotations/ endpoint to manage operations on all quotations.

Both parts perform similar operations. Let's consider both separately. First, let's look at the requests that are sent via commerce. Requests to the B2B project via Commerce are sent to /api/v1/my-quotations/.

List Quotations

Example Request

curl --location 'http://{B2B_URL}/api/v1/my-quotations/' \
--header 'Authorization: Token {token}'

Example Response (200 OK)

{
"count": 1,
"next": "",
"previous": null,
"results": [
{
"id": 89,
"number": "351284518745",
"total_amount": "69.97",
"net_amount": "69.97",
"name": "Test",
"user": {
"id": 268,
"first_name": "first",
"last_name": "last",
"email": "akinon@akinon.com",
"division": {
"id": 1,
"name": "Akinon Main Division",
"phone_number": "02123332211",
"erp_code": "AKI01"
}
},
"created_at": "2023-11-30T13:34:44.520172Z",
"modified_at": "2023-12-04T17:46:00.668207Z",
"status": "cancelled"
}
]
}

Users can filter quotations by name, user, status, total_amount, created_at, modified_at, division and phone_number. For example:

curl --location '{B2B_Backend_URL}/api/v1/my-quotations/?status=cancelled' \
--header 'Authorization: Token {token}'

List Quotations Detail

There are eight different statuses for quotations. These are cancelled, request_approval, pending, draft, sending_approval_request, approved, rejected and expired.

  • Cancelled: The quotation has been canceled by the owner.
  • Request Approval: Created by a sub-division, awaiting approval from the main division.
  • Pending: Approved by the main division or created by a division, awaiting approval from the superuser.
  • Draft: Used by the superuser to edit the quotation.
  • Sending Approval Request: Utilized by the superuser to send the quotation to the owner for approval.
  • Approved: Successfully approved by the superuser and is ready for ordering.
  • Rejected: Rejected either by the superuser or the main division.
  • Expired: The quotation has expired.

Example Request

curl --location '{B2B_Backend_URL}/api/v1/my-quotations/<quotation.id>/' \
--header 'Authorization: Token {token}'

Example Response (200 OK)

{
"id": 88,
"number": "257932207177",
"total_amount": "39.98",
"net_amount": "39.98",
"name": "segment quotation test",
"user": {
"id": 2,
"first_name": "first",
"last_name": "last",
"email": "akinon@akinon.com",
"division": {
"id": 1,
"name": "Akinon Main Division",
"phone_number": "02123332211",
"erp_code": "AKI01"
}
},
"created_at": "2023-11-29T11:38:52.208717Z",
"modified_at": "2023-11-29T11:39:09.283115Z",
"status": "approved",
"quotation_items": [
{
"product_remote_id": 1,
"quantity": 2,
"price": "19.99",
"total_amount": "39.98",
"product": {
"sku": "dummy01",
"name": "dummy",
"price": "19.99",
"asorti": "1573772",
"category": "Şapka",
"currency": "try",
"variants": {},
"product_image": "https://<address>/file.jpg"
},
"divisions": [
{
"id": 1,
"name": "Akinon Main Division",
"address": "221B Baker Street, London center. k",
"erp_code": "AKI01",
"quantity": 2
}
]
}
],
"discount": null,
"expiration_date": "2023-12-14T11:38:52.208517Z",
"segment_remote_id": 3,
"comments": [
{
"id": 291,
"user": {
"id": 38,
"first_name": "first",
"last_name": "last",
"email": "akinon@akinon.com",
"division": {
"id": 1,
"name": "Akinon Main Division",
"phone_number": "02123332211",
"erp_code": "AKI01"
}
},
"comment_type": "approval",
"text": "it is ok.",
"created_at": "2023-12-05T14:56:06.771530Z",
"modified_at": "2023-12-05T14:56:06.771556Z"
},
]
}

Create Quotation

Before creating a quotation, users have to add products to their basket.

Example Request

curl --location '{B2B_Backend_URL}/api/v1/my-quotations/' \
--header 'Content-Type: application/json' \
--header 'Authorization: Token {token}' \
--data '{
"name": "Quotation 1"
}'

Example Response (200 OK)

{
"name": "Quotation 1"
}

Cancel Quotation

After the create quotation users can cancel & reject their quotation from the my-quotations endpoint but can not approve. Because firstly, the quotation should be sent to the divisions for approval. Once the quotation is approved, it is sent back to the quotation owners for their approval. Following their approval, the quotation can then be converted into orders.

Example Request

curl --location '{B2B_Backend_URL}/api/v1/my-quotations/<quotation.id>/cancel/' \
--header 'Content-Type: application/json' \
--header 'Authorization: Token {token}' \
--data '{
"reason": "I dont want to do it"
}'

Reject Quotation

In order to reject a quotation, you must be the owner of the quotation or be affiliated with the main-division.

Example Request

curl --location '{B2B_Backend_URL}/api/v1/my-quotations/<quotation.id>/reject/' \
--header 'Content-Type: application/json' \
--header 'Authorization: Token {token}' \
--data '{
"reason": "I dont want to do it"
}'

To see the comments of a quotation use the following API:

curl --location 'http://{B2B_Backend_URL}/api/v1/my-quotations/<quotation.id>/comments/' \
--header 'Authorization: Token {token}'

To Add comment for a quotation use the following API:

curl --location 'http://{B2B_Backend_URL}/api/v1/my-quotations/<quotation.id>/comments/' \
--header 'Authorization: Token {token}'

Approve Pending Request Approval Quotation

Approve for Pending Quotation use the following API: Requests created by sub-division users wait as request_approval before becoming requests as status. In this section, request_approval is used to approve the pending requests and put them on pending. If the quotation's status is set to request_approval and the creator user is affiliated with the main division, one can approve the quotation. If the quotation status is different or the user's division type is not main, the request will not be successful.

Example Request

curl --location --request POST '{B2B_Backend_URL}/api/v1/my-quotations/<quotation.id>/approve_pending/' \
--header 'Authorization: Token {token}'

Approve Quotation

Requests created by the sub-division users pass to the "sending_request_approval" status after they are approved by the parent dealer. Here it waits for the bidder's approval.

Example Request

curl --location '{B2B_Backend_URL}/api/v1/my-quotations/<quotation.id>/approve/' \
--header 'Content-Type: application/json' \
--header 'Authorization: Token {token}' \
--data '{
"text": "ok"
}'

Admin Operations on Quotations

List Quotations

Example Request

curl --location '{B2B_Backend_URL}/api/v1/quotations/' \
--header 'Authorization: Token {token}'

Users can filter quotations by name, user, status, total_amount, created_at, modified_at, division and phone_number.

curl --location '{B2B_Backend_URL}/api/v1/quotations/?number=593075984145' \
--header 'Authorization: Token {token}'

List Quotations Detail

There are eight different statuses for quotations. These are cancelled, request_approval, pending, draft, sending_approval_request, approved, rejected and expired.

  • Cancelled: The quotation has been canceled by the owner.
  • Request Approval: Created by a sub-division, awaiting approval from the main division.
  • Pending: Approved by the main division or created by a division, awaiting approval from the superuser.
  • Draft: Used by the superuser to edit the quotation.
  • Sending Approval Request: Utilized by the superuser to send the quotation to the owner for approval.
  • Approved: Successfully approved by the superuser and is ready for ordering.
  • Rejected: Rejected either by the superuser or the main division.
  • Expired: The quotation has expired.

Example Request

curl --location '{B2B_Backend_URL}/api/v1/quotations/<quotation.id>/' \
--header 'Authorization: Token {token}'

List Quotation Comments

Example Request

curl --location '{B2B_Backend_URL}/api/v1/quotations/<quotation.id>/comments/' \
--header 'Authorization: Token {token}'

Example Response (200 OK)

[
{
"id": 288,
"user": {
"id": 268,
"first_name": "first",
"last_name": "last",
"email": "akinon@akinon.com",
"division": {
"id": 1,
"name": "Akinon Main Division",
"phone_number": "02123332211",
"erp_code": "AKI01"
}
},
"comment_type": "rejection",
"text": "text for rejection",
"created_at": "2023-12-05T11:55:54.175573Z",
"modified_at": "2023-12-05T11:55:54.175593Z"
}
]

Add Product to Quotation

Example Request

curl --location '{B2B_Backend_URL}/api/v1/quotations/<quotation.id>/add_product_by_sku/' \
--header 'Authorization: Token {token}'
--header 'Content-Type: application/json' \
--data '{
"division": 2,
"quantity": 1,
"sku": "dummy01"
}'

Example Response (200 OK)

{
"id": 76,
"number": "63779097837",
"total_amount": "389.83",
"net_amount": "369.84",
"name": "without segment id",
"user": {
"id": 38,
"first_name": "first",
"last_name": "last",
"email": "akinon@akinon.com",
"division": {
"id": 1,
"name": "Akinon Main Division",
"phone_number": "02123332211",
"erp_code": "AKI01"
}
},
"created_at": "2023-11-22T07:23:10.979832Z",
"modified_at": "2023-12-05T14:41:34.014032Z",
"status": "draft",
"quotation_items": [
{
"product_remote_id": 1,
"quantity": 16,
"price": "19.99",
"total_amount": "319.84",
"product": {
"sku": "dummy01",
"name": "dummy",
"price": "19.99",
"asorti": "1573772",
"category": "Şapka",
"currency": "try",
"variants": {},
"product_image": "https://file.jpg"
},
"divisions": [
{
"id": 2,
"name": "SADA",
"address": "Sada",
"erp_code": "213213",
"quantity": 1
},
{
"id": 1,
"name": "Akinon Main Division",
"address": "221B Baker Street, London center. k",
"erp_code": "AKI01",
"quantity": 16
}
]
},
],
"discount": null,
"expiration_date": "2023-12-07T07:23:10.979628Z",
"segment_remote_id": null
}

Add Comments to Quotation

Example Request

curl --location '{B2B_Backend_URL}/api/v1/quotations/<quotation.id>/comments/' \
--header 'Authorization: Token {token}'
--header 'Content-Type: application/json' \
--data '{
"text": "Comment 1"
}'

Example Response (200 OK)

{
"id": 290,
"user": {
"id": 38,
"first_name": "first",
"last_name": "last",
"email": "akinon@akinon.com",
"division": {
"id": 1,
"name": "Akinon Main Division",
"phone_number": "02123332211",
"erp_code": "AKI01"
}
},
"comment_type": "conversation",
"text": "Comment 1",
"created_at": "2023-12-05T14:45:26.421232Z",
"modified_at": "2023-12-05T14:45:26.421253Z"
}

Create Discount for Quotation

There are two different discount types, percentage and fixed. percentage is used to define a 'percentage' discount on the price. Used 'fixed' when you want to apply a fixed price discount.

Example Request

curl --location '{B2B_Backend_URL}/api/v1/quotations/<quotation.id>/discount/' \
--header 'Authorization: Token {token}'
--header 'Content-Type: application/json' \
--data '{
"value": "10",
"discount_type": "percentage" # or "fixed"
}'

Example Response (200 OK)

{
"id": 298,
"value": "10.00",
"discount_type": "percentage",
"discount_amount": "38.98",
"net_amount": "350.85",
"created_at": "2023-12-05T14:47:09.059855Z",
"modified_at": "2023-12-05T14:47:09.059889Z"
}

Delete Discount for Quotation

Example Request

curl --location --request DELETE '{B2B_Backend_URL}/api/v1/quotations/<quotation.id>/discount/' \
--header 'Authorization: Token {token}' \
--header 'Content-Type: application/json' \
--data '{
"value": "12",
"discount_type": "percentage"
}'

Update Quotation

Example Request

curl --location --request PUT '{B2B_Backend_URL}/api/v1/quotations/<quotation.id>/' \
--header 'Authorization: Token {token}'\
--header 'Content-Type: application/json' \
--data '{
"product_remote_id": 1,
"division": 1,
"quantity": 5
}'

Example Response (200 OK)

{
"id": 76,
"number": "63779097837",
"total_amount": "169.94",
"net_amount": "169.94",
"name": "without segment id",
"user": {
"id": 38,
"first_name": "first",
"last_name": "last",
"email": "akinon@akinon.com",
"division": {
"id": 1,
"name": "Akinon Main Division",
"phone_number": "02123332211",
"erp_code": "AKI01"
}
},
"created_at": "2023-11-22T07:23:10.979832Z",
"modified_at": "2023-12-05T14:53:29.425783Z",
"status": "draft",
"quotation_items": [
{
"product_remote_id": 1,
"quantity": 1,
"price": "19.99",
"total_amount": "19.99",
"product": {
"sku": "dummy01",
"name": "dummy",
"price": "19.99",
"category": "Şapka",
"currency": "try",
"variants": {},
"base_code": "1573772",
"product_image": "https://file.jpg"
},
"divisions": [
{
"id": 2,
"name": "SADA",
"address": "ASDASDA asd as da sd as das asdS",
"erp_code": "213213",
"quantity": 1
},
{
"id": 1,
"name": "Akinon Main Division",
"address": "221B Baker Street, London center. k",
"erp_code": "AKI01",
"quantity": 5
}
]
}
],
"discount": null,
"expiration_date": "2023-12-07T07:23:10.979628Z",
"segment_remote_id": null
}

Set Quotation Status as Draft

Example Request

curl --location --request POST '{B2B_Backend_URL}/api/v1/quotations/<quotation.id>/draft/' \
--header 'Authorization: Token {token}'

Approve Quotation

After the quotation is approved, orders are created on the b2b according to the division count in quotation and B2B_BULK_PROCESSES_BATCH_SIZE environment variable. Let's say that the quotation below is approved and B2B_BULK_PROCESSES_BATCH_SIZE value is 500.

ProductDivisionQuantity
Product XDivision A600
Product YDivision A300
Product XDivision B300

Since the environment value of B2B_BULK_PROCESSES_BATCH_SIZE is 500, orders are divided into pieces of 500.

Following orders will be created.

Order 1:
Division A − Product X * 500

Order 2:
Division A − Product X * 100 − Product Y * 300

Order 3:
Division B − Product X * 300

Example Request

curl --location '{B2B_Backend_URL}/api/v1/quotations/<quotation.id>/approve/' \
--header 'Authorization: Token {token}'\
--header 'Content-Type: application/json' \
--data '{
"text": "it is ok."
}'

Example Response (200 OK)

{
"id": 76,
"number": "63779097837",
"total_amount": "169.94",
"net_amount": "169.94",
"name": "without segment id",
"user": {
"id": 38,
"first_name": "first",
"last_name": "last",
"email": "akinon@akinon.com",
"division": {
"id": 1,
"name": "Akinon Main Division",
"phone_number": "02123332211",
"erp_code": "AKI01"
}
},
"created_at": "2023-11-22T07:23:10.979832Z",
"modified_at": "2023-12-05T14:56:06.694967Z",
"status": "approved",
"quotation_items": [
{
"product_remote_id": 1,
"quantity": 5,
"price": "19.99",
"total_amount": "99.95",
"product": {
"sku": "dummy01",
"name": "dummy",
"price": "19.99",
"asorti": "1573772",
"category": "Şapka",
"currency": "try",
"variants": {},
"product_image": "https://file.jpg"
},
"divisions": [
{
"id": 2,
"name": "SADA",
"address": "ASDASDA asd as da sd as das asdS",
"erp_code": "213213",
"quantity": 1
},
{
"id": 1,
"name": "Akinon Main Division",
"address": "221B Baker Street, London center. k",
"erp_code": "AKI01",
"quantity": 5
}
]
}
],
"discount": null,
"expiration_date": "2023-12-07T07:23:10.979628Z",
"segment_remote_id": null
}

Get Quotation Orders

There are three status for orders. These are pending, created and failed. Once orders are created, they enter the "pending" status. This means that the Order is waiting to be created as an order on commerce. When the order is created on commerce, the status is updated to “created”. If an error occurs during this process, the "failed" status is used.

Example Request

curl --location '{B2B_Backend_URL}/api/v1/quotations/<quotation.id>/orders/' \
--header 'Authorization: Token {token}''

Example Response (200 OK)

[
{
"id": 206,
"remote_number": "2465661458111961",
"division": {
"id": 2,
"name": "SADA",
"phone_number": "05XXXXXXXXX",
"erp_code": "213213"
},
"order_items": [
{
"id": 174,
"product_remote_id": 1,
"quantity": 1,
"data": {
"sku": "dummy01",
"name": "dummy",
"price": "19.99",
"category": "Şapka",
"currency": "try",
"variants": {},
"base_code": "1573772",
"product_image": "https://file.jpg"
},
"created_at": "2023-12-05T14:56:06.716593Z",
"modified_at": "2023-12-05T14:56:06.716606Z"
}
],
"expected_amount": "19.99",
"expected_net_amount": "19.99",
"discount_amount": "0.00",
"created_at": "2023-12-05T14:56:06.713154Z",
"modified_at": "2023-12-05T14:56:09.057338Z",
"status": "created"
}
]

Reject Quotation

In order to reject a quotation, you must be the owner of the quotation or be affiliated with the main-division.

Example Request

curl --location '{B2B_Backend_URL}/api/v1/quotations/<quotation.id>/reject/' \
--header 'Authorization: Token {token}' \
--header 'Content-Type: application/json' \
--data '{
"reason": "I don'\''t like it."
}'

Send Approval Request to Quotation

Example Request

curl --location --request POST '{B2B_Backend_URL}/api/v1/quotations/<quotation.id>/send_approval_request/' \
--header 'Authorization: Token {token}''

Trigger Order Creation

Example Request

curl --location '{B2B_Backend_URL}/api/v1/quotations/<quotation.id>/trigger_order_creation/' \
--header 'Authorization: Token {token}' \
--header 'Content-Type: application/json' \
--data '{
"order": 76
}'

Export Quotations

Exports existing quotations based on the specified query parameters. Returns a cache key for status tracking.

Request Parameters

ParameterDescription
fieldsSpecifies the fields to be included in the export file. Available fields: product_remote_id, quantity, price, total_amount, product, divisions
formatSpecifies the file format for the export. Acceptable values are csv and xls. The default is xls.
status_cache_keyA query parameter to track the status of the file export using the cache key returned from the initial request.

Example Request

curl --location --request GET '{B2B_Backend_URL}/api/v1/quotations/?fields=name&fields=total_amount' \
--header 'Authorization: Token {token} \
--header 'Content-Type: application/json'

Example Response (200 OK)

{
"cache_key": "beacaa8ba65571e3840e28a11f17481e"
}

Export File Status

Checks the status of an export file using the cache key obtained from the export request. Provides information on whether the file is ready for download.

Example Request

curl --location '{B2B_Backend_URL}/api/v1/quotations/?status_cache_key=beacaa8ba65571e3840e28a11f17481e' \
--header 'Authorization: Token {token}'

Example Response

{
"is_ready": true,
"url": "{url}/export_file/beacaa8ba65571e3840e28a11f17481e.xls",
"status": "completed"
}

Response Parameters

FieldDescription
is_readyIndicates whether the file is ready for download (true or false).
urlThe URL to download the exported file once it is ready.
statusProvides the current status of the export process (e.g., waiting, completed).