編集: 複数の opps を同時に追加する方法を示す完全なオーバーホール。何らかの方法でそれらの作成をずらすことができる場合に役立つはずです(それらをローカルデータベースに保存し、カップルを取得した/十分な時間が経過した/ユーザーが「キューをフラッシュする」ボタンを押した場合にのみアップロードします)。
警告、コードは実際にはより恐ろしく見えます。最初に編集履歴で以前のバージョンを確認したほうがよいかもしれません。
2 つのパラメータを持つ受信リクエストを受け入れ、それらを挿入しようとする Apex クラスを作成するのはそれほど難しくありません。Setup->Develop->Classes->New に移動して、これを試してください:
global with sharing class OpportunityLinkedInsert{
static webservice Opportunity insertSingle(Opportunity opp, OpportunityLineItem[] lines){
if(opp == null || lines == null){
throw new IntegrationException('Invalid data');
}
Opportunity[] result = insertMultiple(new List<Opportunity>{opp}, new List<List<OpportunityLineItem>>{lines});
return result[0]; // I imagine you want the Id back :)
}
/* I think SOAP doesn't handle method overloading well so this method has different name.
'lines' are list of lists (jagged array if you like) so opps[i] will be inserted and then lines[i] will be linked to it etc.
You can insert up to 10,000 rows in one go with this function (remember to count items in both arrays).
*/
static webservice List<Opportunity> insertMultiple(List<Opportunity> opps, List<List<OpportunityLineItem>> lines){
if(opps == null || lines == null || opps.size() == 0 || opps.size() != lines.size()){
throw new IntegrationException('Invalid data');
}
insert opps;
// I need to flatten the structure before I insert it.
List<OpportunityLineItem> linesToInsert = new List<OpportunityLineItem>();
for(Integer i = 0; i < opps.size(); ++i){
List<OpportunityLineItem> linesForOne = lines[i];
if(linesForOne != null && !linesForOne.isEmpty()){
for(Integer j = 0; j < linesForOne.size(); ++j){
linesForOne[j].OpportunityId = opps[i].Id;
}
linesToInsert.addAll(linesForOne);
}
}
insert linesToInsert;
return opps;
}
// helper class to throw custom errors
public class IntegrationException extends Exception{}
}
これが本番組織に送られる前に、単体テストクラスも必要です。そのようなことを行う必要があります(100%使用できるようにするには、さらにいくつかのことで満たす必要があります。詳細については、この質問を参照してください)。
@isTest
public class OpportunityLinkedInsertTest{
private static List<Opportunity> opps;
private static List<List<OpportunityLineItem>> items;
@isTest
public static void checSingleOppkErrorFlow(){
try{
OpportunityLinkedInsert.insertSingle(null, null);
System.assert(false, 'It should have failed on null values');
} catch(Exception e){
System.assertEquals('Invalid data',e.getMessage());
}
}
@isTest
public static void checkMultiOppErrorFlow(){
prepareTestData();
opps.remove(1);
try{
OpportunityLinkedInsert.insertMultiple(opps, items);
System.assert(false, 'It should have failed on list size mismatch');
} catch(Exception e){
System.assertEquals('Invalid data',e.getMessage());
}
}
@isTest
public static void checkSuccessFlow(){
prepareTestData();
List<Opportunity> insertResults = OpportunityLinkedInsert.insertMultiple(opps, items);
List<Opportunity> check = [SELECT Id, Name,
(SELECT Id FROM OpportunityLineItems)
FROM Opportunity
WHERE Id IN :insertResults
ORDER BY Name];
System.assertEquals(items[0].size(), check[0].OpportunityLineItems.size(), 'Opp 1 should have 1 product added to it');
System.assertEquals(items[1].size(), check[0].OpportunityLineItems.size(), 'Opp 3 should have 1 products');
}
// Helper method we can reuse in several tests. Creates 2 Opportunities with different number of line items.
private static void prepareTestData(){
opps = new List<Opportunity>{
new Opportunity(Name = 'Opp 1', StageName = 'Prospecting', CloseDate = System.today() + 10),
new Opportunity(Name = 'Opp 2', StageName = 'Closed Won', CloseDate = System.today())
};
// You might have to fill in more fields here!
// Products are quite painful to insert with all their standard/custom pricebook dependencies etc...
items = new List<List<OpportunityLineItem>>{
new List<OpportunityLineItem>{
new OpportunityLineItem(Description = 'Opp 1, Product 1', Quantity = 1, UnitPrice = 10)
},
new List<OpportunityLineItem>{
new OpportunityLineItem(Description = 'Opp 2, Product 1', Quantity = 1, UnitPrice = 10),
new OpportunityLineItem(Description = 'Opp 2, Product 2', Quantity = 1, UnitPrice = 10),
new OpportunityLineItem(Description = 'Opp 2, Product 3', Quantity = 1, UnitPrice = 10)
}
};
}
}
これは、Apex コードに関してはほぼ同じです。
いずれかの挿入が失敗すると、SOAP 例外が返されます。これは、トランザクション、 ACIDなどの点でも少し優れています。行項目の挿入が失敗した場合、PHP 側からクリーンアップする準備はできていますか? 自動メール通知などが Salesforce で設定され、すでに送信されている場合はどうなりますか? Apex への 1 回の呼び出しでそれを行うと、データベースでストアド プロシージャが機能するのとほぼ同じように、要求全体が確実にロールバックされます。
これらのクラスをサンドボックスで作成してから、クラスのリストで最初のクラスを見つけてください。PHP クラスの生成に使用できる WSDL ファイルを生成するためのリンクがあります。2 番目のものに移動すると、[Run Tests] ボタンが表示されます。テストを本番組織にプッシュする前に、テストが合格することを確認する必要がありますが、それはプラットフォーム上でのプログラミングのまったく新しい世界です :)