本指南阐明了提案的定义,并逐步说明了如何通过 API 创建 Proposal 对象。此外,本指南还介绍了在创建提案后可执行的后续步骤。
基础入门
DFP 销售管理系统中的提案代表 DFP 广告管理系统(以下简称 DFP)内尚未进入广告投放管理阶段的具体商机。它们汇总了订单的结算详情,包括分配给交易的预算、分配的负责管理流程的销售人员和广告投放人员,以及按提案订单项的形式出售的广告资源。
通过 API 创建提案
要创建 Proposal
对象,您只需填写一个必填字段(即“名称”字段)即可。
Java
// Get the ProposalService. ProposalServiceInterface proposalService = dfpServices.get(session, ProposalServiceInterface.class); // Create a proposal. Proposal proposal = new Proposal(); proposal.setName("Proposal #" + new Random().nextInt(Integer.MAX_VALUE));
Python
# Initialize appropriate services. proposal_service = client.GetService('ProposalService', version='v201805') # Create proposal objects. proposal = { 'name': 'Proposal #%s' % uuid.uuid4(), ...
PHP
$proposalService = $serviceFactory->createProposalService($session); // Create a proposal. $proposal = new Proposal(); $proposal->setName('Proposal #' . uniqid());
C#
using (ProposalService proposalService = (ProposalService) user.GetService(DfpService.v201805.ProposalService)) // Create a proposal. Proposal proposal = new Proposal(); proposal.name = "Proposal #" + new Random().Next(int.MaxValue);
其余字段是可供销售规划团队以后填写的设置。只要在提案提交之前填好广告投放管理所需的必填字段,相关提案就可以分阶段运行。用于提交提案的必填字段会将此提案与广告客户关联起来。
Java
// Create a proposal company association. ProposalCompanyAssociation proposalCompanyAssociation = new ProposalCompanyAssociation(); proposalCompanyAssociation.setCompanyId(advertiserId); proposalCompanyAssociation.setType(ProposalCompanyAssociationType.ADVERTISER); proposal.setAdvertiser(proposalCompanyAssociation);
Python
... 'advertiser': { 'companyId': advertiser_id, 'type': 'ADVERTISER' }, ...
PHP
// Create a proposal company association. $proposalCompanyAssociation = new ProposalCompanyAssociation(); $proposalCompanyAssociation->setCompanyId($advertiserId); $proposalCompanyAssociation->setType(ProposalCompanyAssociationType::ADVERTISER); $proposal->setAdvertiser($proposalCompanyAssociation);
C#
// Create a proposal company association. ProposalCompanyAssociation proposalCompanyAssociation = new ProposalCompanyAssociation(); proposalCompanyAssociation.companyId = advertiserId; proposalCompanyAssociation.type = ProposalCompanyAssociationType.ADVERTISER; proposal.advertiser = proposalCompanyAssociation;
如果与此提案关联的公司有任何需要附加的联系人,则可通过在 proposalCompanyAssociation
对象中设置 ID 列表来附加:
Java
proposalCompanyAssociation.setContactIds(new long[] {INSERT_YOUR_LIST_OF_CONTACTS_HERE}); proposal.setAdvertiser(proposalCompanyAssociation);
Python
... 'advertiser': { 'companyId': advertiser_id, 'type': 'ADVERTISER', 'contactIds': [INSERT_YOUR_LIST_OF_CONTACTS_HERE] }, ...
PHP
$proposalCompanyAssociation->contactIds = array(INSERT_YOUR_LIST_OF_CONTACTS_HERE); $proposal->advertiser = $proposalCompanyAssociation;
C#
proposalCompanyAssociation.contactIds = new long[] {INSERT_YOUR_LIST_OF_CONTACTS_HERE}; proposal.advertiser = proposalCompanyAssociation;
在推送到 DFP 之前,必须设置主要销售人员,但辅助销售人员可以视需要进行设置。要分配销售人员,请创建 SalespersonSplit 对象。通过此对象,您可以设置相应销售人员的用户 ID 及其对应的分配百分比。然后,对每个辅助销售人员执行相同的操作。完成此操作后,您可以通过 SalespersonSplit
对象将主要销售人员和辅助销售人员与相关提案直接关联起来。
Java
// Create salesperson splits for the primary salesperson and secondary salespeople. SalespersonSplit primarySalesperson = new SalespersonSplit(); primarySalesperson.setUserId(primarySalespersonId); primarySalesperson.setSplit(75000); proposal.setPrimarySalesperson(primarySalesperson); SalespersonSplit secondarySalesperson = new SalespersonSplit(); secondarySalesperson.setUserId(secondarySalespersonId); secondarySalesperson.setSplit(25000); proposal.setSecondarySalespeople(new SalespersonSplit[] {secondarySalesperson});
Python
... 'primarySalesperson': { 'userId': primary_salesperson_id, 'split': '75000' }, 'secondarySalespeople': [{ 'userId': secondary_salesperson_id, 'split': '25000' }], ...
PHP
// Create salesperson splits for the primary salesperson and secondary // salespeople. $primarySalesperson = new SalespersonSplit(); $primarySalesperson->setUserId($primarySalespersonId); $primarySalesperson->setSplit(75000); $proposal->setPrimarySalesperson($primarySalesperson); $secondarySalesperson = new SalespersonSplit(); $secondarySalesperson->setUserId($secondarySalespersonId); $secondarySalesperson->setSplit(25000); $proposal->setSecondarySalespeople([$secondarySalesperson]);
C#
// Create salesperson splits for the primary salesperson and secondary salespeople. SalespersonSplit primarySalesperson = new SalespersonSplit(); primarySalesperson.userId = primarySalespersonId; primarySalesperson.split = 75000; proposal.primarySalesperson = primarySalesperson; SalespersonSplit secondarySalesperson = new SalespersonSplit(); secondarySalesperson.userId = secondarySalespersonId; secondarySalesperson.split = 25000; proposal.secondarySalespeople = new SalespersonSplit[] { secondarySalesperson };
Proposal
对象还包含 probabilityOfClose() 字段,您可向其中输入一个十万分率的数值。此字段既能用于在报表中计算收入,也能在工作流程中用作验证字段。
Java
// Set the probability to close to 100%. proposal.setProbabilityOfClose(100000L);
Python
... 'probabilityOfClose': '100000', ...
PHP
// Set the probability to close to 100%. $proposal->setProbabilityOfClose(100000);
C#
// Set the probability to close to 100%. proposal.probabilityOfClose = 100000L;
要提交提案,您必须设置主要的广告投放人员。
Java
// Set the primary trafficker on the proposal for when it becomes an order. proposal.setPrimaryTraffickerId(primaryTraffickerId);
Python
... 'primaryTraffickerId': primary_trafficker_id, ...
PHP
// Set the primary trafficker on the proposal for when it becomes an order. $proposal->setPrimaryTraffickerId($primaryTraffickerId);
C#
// Set the primary trafficker on the proposal for when it becomes an order. proposal.primaryTraffickerId = primaryTraffickerId;
此提案还必须分配有预算。您可以通过创建 Money 对象完成此操作,其中需要指定极少的金额以及货币代码(必须指定该代码,并且它应与提案设置中使用的货币一致)。
Java
// Create a budget for the proposal worth 100 in the network local currency. Money budget = new Money(); budget.setMicroAmount(100000000L); budget.setCurrencyCode(networkService.getCurrentNetwork().getCurrencyCode()); proposal.setBudget(budget);
Python
... 'budget': { 'microAmount': '100000000', 'currencyCode': network_service.getCurrentNetwork()['currencyCode'] }, ...
PHP
// Create a budget for the proposal worth 100 in the network local currency. $budget = new Money(); $budget->setMicroAmount(100000000); $budget->setCurrencyCode( $networkService->getCurrentNetwork() ->getCurrencyCode() ); $proposal->setBudget($budget);
C#
// Create a budget for the proposal worth 100 in the network local currency. Money budget = new Money(); budget.microAmount = 100000000L; budget.currencyCode = networkService.getCurrentNetwork().currencyCode; proposal.budget = budget;
结算字段指定了所投放展示的结算方式,以及在进行此类计算时需要使用的投放数据。这些字段均为选填字段,并会提供默认值。
Java
proposal.setBillingCap(BillingCap.CAPPED_CUMULATIVE); proposal.setBillingSource(BillingSource.DFP_VOLUME);
Python
... 'billingCap': 'CAPPED_CUMULATIVE', 'billingSource': 'DFP_VOLUME' ...
PHP
$proposal->setBillingCap(BillingCap::CAPPED_CUMULATIVE); $proposal->setBillingSource(BillingSource::DFP_VOLUME);
C#
proposal.billingCap = BillingCap.CAPPED_CUMULATIVE; proposal.billingSource = BillingSource.DFP_VOLUME;
设置完这些字段后,您便可通过对一组提案对象调用 createProposals 来新建 Proposal
对象:
Java
// Create the proposal on the server. Proposal[] proposals = proposalService.createProposals(new Proposal[] {proposal});
Python
# Add proposals. proposals = proposal_service.createProposals([proposal])
PHP
// Create the proposals on the server. $proposals = $proposalService->createProposals([$proposal]);
C#
// Create the proposal on the server. Proposal[] proposals = proposalService.createProposals(new Proposal[] { proposal });
由于提案通常是由 ProposalLineItem 对象组成,因此下一步就是在新建的提案下添加提案订单项。添加完提案订单项后,您就可以提交此提案进行审批了。
程序化
您和买方通过程序化提案进行互动。您可以通过设置 ProposalMarketplaceInfo.buyerAccountId 字段来指定买方。使用 Programmatic_Buyer PQL 表格可获取有效的买方 ID。ProposalMarketplaceInfo 上的大多数其他字段都是只读字段,可用于确定程序化提案的状态以及适用的操作。
程序化提案的状态
根据您是否使用销售管理,程序化提案的状态略有不同。您可通过 DFP 帮助中心大致了解使用销售管理和未使用销售管理的程序化提案的对应状态。
以下图表从 API 的角度描述了协商过程中处于不同状态的程序化提案。每个状态由以下字段的各种组合表示:
- ProposalMarketplaceInfo.hasLocalVersionEdits
- ProposalMarketplaceInfo.negotiationStatus
- Proposal.status
协商演示
在这里,我们将向您逐步介绍如何利用 API 就程序化提案与买方达成一致。我们将引用以上图表中的状态。
为让买方接受做好准备
无论您是否使用销售管理,首先您都需要使用要发送给买方的提案订单项草拟一个程序化提案。这属于以上两图中的 state C
。
如果您未使用销售管理,请跳至请求买方接受这一步。如果您在使用销售管理,则需要完成与提案关联的相应内部工作流程(图 1 的 state C to D
)。您可以通过调用 SubmitProposalsForApproval 来完成此流程。
请求买方接受
您准备好让买方查看程序化提案后,便可以使用 RequestBuyerAcceptance 操作来请求买方接受。这时,系统会将您转到协商阶段。
协商
在此阶段,可能会发生以下情况。
- 买方可能未做出任何更改就接受您的程序化提案。
- 买方可能会提议更改。在这种情况下,系统会将提案恢复为草稿状态(以上两图中的
state B
)。然后,您需要打开要修改的提案,实施提议的更改,并将更改后的提案发回给买方进行审核。 - 您可能也会决定做出更改(甚至是在买方回复之前)。如果您在使用销售管理,则可通过执行 RetractProposals 操作来实现这一点。执行该操作后,系统会将您的提案返回到图 1 的
state B
。在此状态下,您可以先打开要修改的提案来做出更改,然后再将其发回给买方。如果您未使用销售管理,则可通过直接在图 2 中的state D
下打开要修改的提案来实现这一点。
直到您与买方达成共识,协商阶段才会结束。使用 getMarketplaceCommentsByStatement 可以检索您和买方之间的评论信息。当提案处于(上方两图中的)state A
状态时,您即可向买方发送评论。为此,您将需要使用 updateProposals 来更新提案中的 marketplaceComment 字段。然后,在您请求买方接受时,系统会将评论发送给买方。
敲定
当您和买方都接受该程序化提案后,便会进入敲定阶段(图 1 的 state E
以及图 2 的 state F
)。然后,DFP 会自动从此程序化提案中创建订单项。
大多数情况下,至此您已完成有关程序化提案的所有操作。不过,在此状态下,您还可以执行以下两项操作:
- 修改提案中与投放相关的字段,以便重新打开程序化提案,从而重新进行协商。如果您在使用销售管理,则可通过执行以下操作来实现这一点:撤消相应提案(图 1 的
state F to B
),然后打开要修改的提案并做出更改,接着通过内部工作流程提交提案,最后请求买方接受。如果您未使用销售管理,则可通过执行以下操作来实现这一点:打开要修改的提案(图 2 的state E to A
)并做出更改,然后请求买方接受。 - 做出与投放无关的修改(例如,更新提案的名称并使这些更改反映到通过此次交易创建的 DFP 订单和订单项中)。如果您在使用销售管理,则可通过执行以下操作来实现这一点:从图 1 的
state F
中撤消提案并做出修改,然后通过内部工作流程提交提案。这样一来,系统就会将您转到图 1 中的state G
;然后,在此状态下,您可以执行 UpdateOrderWithSellerData 操作。如果您未使用销售管理,则可在图 2 中的state E
下做出修改,然后执行UpdateOrderWithSellerData
操作。