CPQ APIを使ってみます



+ [質問:Anyone have experience working on CPQ API? I'am using postman to hit endpoints. Need assistance regarding json body for adding and managing products.](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007WdgwUSAR)

```Json
{
	"context": "{
		\"quote\" : {
			\"record\" : {
				\"attributes\" : {
					\"type\" : \"SBQQ__Quote__c\",
					\"url\" : \"/services/data/v59.0/sobjects/SBQQ__Quote__c/a0q2w000004pwTlAAI\"
				},
				\"Name\" : \"Q-00129\",
				\"Id\" : \"a0q2w000004pwTlAAI\"
			},
			\"nextKey\" : 2,
			\"netTotal\" : 0.00,
			\"lineItems\" : [
				{
					\"record\" : {
						\"attributes\" : {
							\"type\" : \"SBQQ__Product__c\",
							\"SBQQ__Quote__c\" : \"a0q2w000004pwTlAAI\",
							\"SBQQ__Product__c\" : \"01t2w00000EwsmzAAB\",
							\"SBQQ__Number__c\" : 1,
							\"SBQQ__Quantity__c\" : 2.00,
							\"SBQQ__NetTotal__c\" : 99.76 
						},
						\"productQuantityEditable\": true,
						\"productHasDimensions\": false,
						\"key\": 2,
						\"descriptionLocked\": false
					}
				}
			],
			\"lineItemGroups\" : [
				
			],
			\"customerTotal\" : 0.00
		},
		\"products\" : [
			
		],
		\"groupKey\" : 0,
		 \"ignoreCalculate\": true
		}"
	}
 ```

APIの説明
[Add Products API](https://developer.salesforce.com/docs/atlas.en-us.cpq_dev_api.meta/cpq_dev_api/cpq_api_add_products.htm)

とりあえず説明にあるBodyサンプルを送信してみます。例題は３行に分かれていますがこのままではエラーになったので１行にしてから送信します。

:::note alert
Illegal unquoted character ((CTRL-CHAR, code 13)): has to be escaped using backslash to be included in string value at [line:1, column:159]
:::

```Json
{
	"context" : "{
		\"quote\" : {
			\"record\" : {
				\"attributes\" : {
					\"type\" : \"SBQQ__Quote__c\",
					\"url\" : \"/services/data/v41.0/sobjects/SBQQ__Quote__c/a0p61000004IpR8AAK\"
				},
				\"Name\" : \"Q-00905\",
				\"Id\" : \"a0p61000004IpR8AAK\"
			},
			\"nextKey\" : 2,
			\"netTotal\" : 0.00,
			\"lineItems\" : [
				
			],
			\"lineItemGroups\" : [
				
			],
			\"customerTotal\" : 0.00
		},
		\"products\" : [
			
		],
		\"groupKey\" : 0,
		 \"ignoreCalculate\": true
		}"
	}
```

個人的にはSBQQ__Quote__cのIdも正しく設定していないので、エラーを期待したのですがステータスコードは200が返ってきました。質問されている内容と同じですね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/9c497827-280b-4809-771d-5b660faabe31.png)

```json
"{
	\"ui_original_record\" : {
		\"cloneRecordIfNoCache\" : true,
		\"cacheName\" : \"LineEditor\",
		\"cacheId\" : \"a0p61000004IpR8AAK\",
		\"cachedOriginalRecordPath\" : [
			\"quote\",
			\"ui_original_record\"
		]
	},
	\"record\" : {
		\"attributes\" : {
			\"type\" : \"SBQQ__Quote__c\",
			\"url\" : \"/services/data/v59.0/sobjects/SBQQ__Quote__c/a0p61000004IpR8AAK\"
		},
		\"Id\" : \"a0p61000004IpR8AAK\",
		\"Name\" : \"Q-00905\"
	},
	\"nextKey\" : 2,
	\"netTotal\" : 0.00,
	\"lineItems\" : [
		
	],
	\"lineItemGroups\" : [
		
	],
	\"hasMultiSegmentLines\" : false,
	\"customerTotal\" : 0.00
	}"
```

Idの２か所を現存するIdに変更します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/0812adb7-c3ed-ff7c-8686-d4aa6cfd1957.png)

結果は200ですが、画面には表示されませんね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/b07fab4f-ee0e-6944-4ae2-0066b7d27e71.png)

lineItemsがnullだったので、質問主さんのコードを参考に追加しました。

```
\"lineItems\" : [
				
			],
```

しかしエラーですね。

:::note alert
[
    {
        "errorCode": "APEX_ERROR",
        "message": "System.JSONException: \n\n(System Code)"
    }
]
:::

jsonのチェッカーで検証すると問題なさそう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/cdcb804c-a32d-acde-dbd3-bca4ad99f702.png)

色々触るとさらに違うエラー。理解できません。

:::note alert
System.JSONException: Unexpected character ('\"' (code 34)): was expecting comma to separate OBJECT entries at [line:1, column:436]\n\n(System Code)
:::

:::note
{"context": "{\"quote\":{\"record\":{\"attributes\":{\"type\":\"SBQQ__Quote__c\",\"url\":\"/services/data/v59.0/sobjects/SBQQ__Quote__c/a0qHp00000QQMOpIAP\"},\"Name\":\"Q-00000\",\"Id\":\"a0qHp00000QQMOpIAP\"},\"nextKey\":2,\"netTotal\":0.00,\"lineItems\":[ {\"record\" : {\"attributes\" : {\"type\" : \"SBQQ__Product__c\",\"SBQQ__Quote__c\" : \"a0qHp00000QQMOpIAP\",\"SBQQ__Product__c\" : \"a0mHp00000O0DLyIAN\",\"SBQQ__Number__c\" : 1,\"SBQQ__Quantity__c\" : 2.00,\"SBQQ__NetTotal__c\" : 99.76 },\"productQuantityEditable\": true,\"productHasDimensions\": false,\"key\": 2,\"descriptionLocked\": false}} ],\"lineItemGroups\":[],\"customerTotal\":0.00},\"products\":[],\"groupKey\":0, \"ignoreCalculate\": true}"}
:::

lineItemsの中身

:::note
{\"record\" : {\"attributes\" : {\"type\" : \"SBQQ__Product__c\",\"SBQQ__Quote__c\" : \"a0qHp00000QQMOpIAP\",\"SBQQ__Product__c\" : \"a0mHp00000O0DLyIAN\",\"SBQQ__Number__c\" : 1,\"SBQQ__Quantity__c\" : 2.00,\"SBQQ__NetTotal__c\" : 99.76 },\"productQuantityEditable\": true,\"productHasDimensions\": false,\"key\": 2,\"descriptionLocked\": false}}
:::

配列に次のレコードが無いのに ,　をつかたから？

:::note alert
[
    {
        "errorCode": "APEX_ERROR",
        "message": "System.JSONException: Unexpected character (']' (code 93)): expected a value at [line:1, column:430]\n\n(System Code)"
    }
]
:::

lineItemsの形式が違うようなので、サンプルから類推して作り直しました。


```Json
{
	  \"record\": {
		\"attributes\": {
			  \"type\": \"SBQQ__QuoteLine__c\"
		},
		\"SBQQ__Product__c\": \"01tHp00000BClT6IAL\"  
	},
	  \"productQuantityEditable\": true,
	  \"productHasDimensions\": false,
	  \"key\": 1,
	  \"descriptionLocked\": false
}
```

```Json
{  \"record\": {\"attributes\": {  \"type\": \"SBQQ__QuoteLine__c\"},\"SBQQ__Product__c\": \"01tHp00000BClT6IAL\"  },  \"productQuantityEditable\": true,  \"productHasDimensions\": false,  \"key\": 1,  \"descriptionLocked\": false}
```

何故か""が両端についています。しかし200で成功した模様。画面には変化が無い。

```Json
"{
	\"ui_original_record\" : {
		\"cloneRecordIfNoCache\" : true,
		\"cacheName\" : \"LineEditor\",
		\"cacheId\" : \"a0qHp00000QQMOpIAP\",
		\"cachedOriginalRecordPath\" : [
			\"quote\",
			\"ui_original_record\"
		]
	},
	\"record\" : {
		\"attributes\" : {
			\"type\" : \"SBQQ__Quote__c\",
			\"url\" : \"/services/data/v59.0/sobjects/SBQQ__Quote__c/a0qHp00000QQMOpIAP\"
		},
		\"Id\" : \"a0qHp00000QQMOpIAP\",
		\"Name\" : \"Q-00000\"
	},
	\"nextKey\" : 2,
	\"netTotal\" : 2.00,
	\"lineItems\" : [
		{
			\"ui_original_record\" : {
				\"cloneRecordIfNoCache\" : false
			},
			\"record\" : {
				\"attributes\" : {
					\"type\" : \"SBQQ__QuoteLine__c\"
				},
				\"SBQQ__Product__c\" : \"01tHp00000BClT6IAL\",
				\"SBQQ__Number__c\" : 1
			},
			\"productQuantityEditable\" : true,
			\"productHasDimensions\" : false,
			\"key\" : 1,
			\"descriptionLocked\" : false
		}
	],
	\"lineItemGroups\" : [
		
	],
	\"hasMultiSegmentLines\" : false,
	\"customerTotal\" : 0.00
	}"
 ```

 Saveは別のAPIみたいですね。

 + [Save Quote API](https://developer.salesforce.com/docs/atlas.en-us.cpq_dev_api.meta/cpq_dev_api/cpq_quote_api_save_final.htm)

うぁあ、使いにくい。単にId呼び出して保存するだけかと思ったらまた、lineItemsを登録させるみたいだ。こりゃぁ自動化できんな。 ver16から使えるってあるから、きっと古い仕様で作ったAPIだろう。

```Json
{
	"saver": "SBQQ.QuoteAPI.QuoteSaver",
	 "model": "{
		\"record\" : {
			\"attributes\" : {
				\"type\" : \"SBQQ__Quote__c\",
				\"url\" : \"/services/data/v59.0/sobjects/SBQQ__Quote__c/a0qHp00000QQMOpIAP\"
			},
			\"Name\" : \"Q-00000\",
			\"Id\" : \"a0qHp00000QQMOpIAP\"
		},
		\"nextKey\" : 2,
		\"netTotal\" : 0.00,
		\"lineItems\" : [
			{
				  \"record\": {
					\"attributes\": {
						  \"type\": \"SBQQ__QuoteLine__c\"
					},
					\"SBQQ__Product__c\": \"01tHp00000BClT6IAL\"  
				},
				  \"productQuantityEditable\": true,
				  \"productHasDimensions\": false,
				  \"key\": 1,
				  \"descriptionLocked\": false
			}
		],
		\"lineItemGroups\" : [
			
		],
		\"customerTotal\" : 0.00
		}"
	}
 ```

```Json
{"saver": "SBQQ.QuoteAPI.QuoteSaver", "model": "{\"record\":{\"attributes\":{\"type\":\"SBQQ__Quote__c\",\"url\":\"/services/data/v59.0/sobjects/SBQQ__Quote__c/a0qHp00000QQMOpIAP\"},\"Name\":\"Q-00000\",\"Id\":\"a0qHp00000QQMOpIAP\"},\"nextKey\":2,\"netTotal\":0.00,\"lineItems\":[{  \"record\": {\"attributes\": {  \"type\": \"SBQQ__QuoteLine__c\"},\"SBQQ__Product__c\": \"01tHp00000BClT6IAL\"  },  \"productQuantityEditable\": true,  \"productHasDimensions\": false,  \"key\": 1,  \"descriptionLocked\": false}],\"lineItemGroups\":[],\"customerTotal\":0.00}"}
```

画面にも表示された。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/9e1e6755-6440-af65-66d5-fd472a03b764.png)



# 参考資料

https://thecloudupdate.co/enhancing-user-experience-simplifying-product-additions-to-quotes-with-salesforce-cpq-api-and-screen-flows/?trk=public_post_comment-text

https://salesforce.stackexchange.com/questions/383342/salesforce-cpq-api-to-create-quote-and-quote-line-items-facing-issue-with-calcul


# 、バンドル製品とそのオプションを見積明細として追加する際に課題に直面しています。オプション本体を製品と一緒に渡すのに苦労しています。

+ [How do I add bundle products with options using CPQ API?](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007X7eLz)


ご連絡いただきありがとうございます。製品を見積品目として見積書に組み込むことができました。ただし、現在、バンドル製品とそのオプションを見積明細として追加する際に課題に直面しています。オプション本体を製品と一緒に渡すのに苦労しています。

さらに、CPQ API を使用して製品ルールをトリガーする方法を理解することに興味があります。具体的には、API を介して製品を見積に追加し、追加された製品にアクティブなルールが関連付けられている場合、ルールはトリガーされません。CPQ API 経由で製品を追加するときにルールが適切に実行されるようにする方法について教えていただけますか?