How-to: Add a Job (Task) Type๏ƒ

In order to add a new Job Type, the following steps shall be used:

  1. Each job is uniquely identified by two keys: platform and type name. Platform is a value from the ppc_robot_lib.platform.PlatformType enum. Type name is a short identifier which should describe the job type and should be consistent with other platforms, e.g. custom_report, url_check_report, ad_multivariate_test_report and so on.

  2. Create a new subpackage in ppc_robot_task_types/<platform>/<task_type> (e.g. ppc_robot_task_types/adwords/custom_report). The __init__.py file can be blank.

  3. Create your first version of the report: create a module named <type_name>_v1.py. The file should contain a class named TypeNameV1 that implements the ppc_robot_lib.tasks.abstract_task_type.AbstractReportType:

    from typing import Any, Dict
    
    from ppc_robot_lib.platform import PlatformType
    from ppc_robot_lib.tasks.abstract_task_type import AbstractReportType
    
    class TypeNameV1(AbstractReportType):
        @classmethod
        def get_name(cls) -> str:
            return 'type_name'  # Short type name.
    
        @classmethod
        def get_platform(cls) -> PlatformType:
            return PlatformType.ADWORDS  # Return the correct platform constant.
    
        @classmethod
        def get_version(cls):
            return 1  # Return the version
    
        @classmethod
        def get_level(cls) -> TaskLevel:
            return TaskLevel.CLIENT_ACCOUNT
    
        @classmethod
        def get_description(cls) -> TaskDescription:
            # Gets the task description displayed in the interface. See the TaskDescription object for available fields.
            return TaskDescription(
                title='My First Task Type',
                short_description='Short task type description',
                description='<p>Longer description, HTML can be used.</p>',
            )
    
        @classmethod
        def upgrade_from_previous(cls, parameters: Dict[str, Any]) -> Dict[str, Any]:
            # Should upgrade parameters if they changed in the new version.
            # Since this is the first version, we can safely return the input parameters.
            return parameters
    
        @classmethod
        def get_default_parameters(cls) -> Dict[str, Any]:
            return {}  # Return default parameters.ยจ
    
        def execute(self, parameters: Dict[str, Any]):
            pass
    

Note

Pay extra attention to the get_level() method. This method determines level of objects on which the task operates. By returning TaskLevel.SERVICE_ACCOUNT, you will instruct PPC Robot that the report is not created for individual Client Account, but for a whole Service Account.

This means that the user will not be able to select individual account in the last step of record creation and Service Account Selection will have be done in the second step. This is used for Managed Accounts (MCC) overview reports, so make sure you check this method when copying code from other reports!

  1. Implement the execute() method. This method is called when the report is run. You can use any of the Reporting Functions.

    Example:

    from ppc_robot_lib.adwords import Query
    from ppc_robot_lib.output.types import Table
    from ppc_robot_lib.reporting.input import download_adwords_report
    from ppc_robot_lib.reporting.output import write_tables
    from ppc_robot_lib.utils.types import Column
    
    class TypeNameV1(AbstractReportType):
        # ... other methods ...
    
        def execute(self, parameters: Dict[str, Any]):
            # Download a report.
            query = Query(
                select=['AccountDescriptiveName', 'Clicks'],
                from_report='ACCOUNT_PERFORMANCE_REPORT'
            )
            report = download_adwords_report(query)
    
            # Output the table.
            write_tables([
                Table(
                    report,
                    sheet_name='Report',
                    header=[
                        Column('Account Name', 'AccountDescriptiveName'),
                        Column('Total Clicks', 'Clicks'),
                    ]
                )
            ])
    
  2. Testing the job type: you can test the job type without the user interface or any additional dependencies (however, it is recommended to start the rate limiter before you start testing your job).

    1. In the dev_scripts/reports folder, create a new JSON file, for example task_type.json (the name is not significant). The contents of the file should look like this:

      {
        "platform": "adwords",
        "taskType": "type_name",
        "taskTypeVersion": 1,
        "parameters": {
        }
      }
      

      The parameters dictionary will be passed directly to your report type, so fill-in the values accordingly to your task type.

    2. Run the following script (you can also create a new PyCharm configuration):

      $ python dev_scripts/test_report.py -c ID dev_scripts/reports/task_type.json
      

      Where ID is an ID of ClientAccount in the database that sould be used for the test. Look for rows in the robot_client_accounts table.

  3. You should have a working job type by now. The type will already be available in the interface for selection, but there is no interface for entering parameters for this type. You have to create a so-called parameter editor, which is a Vue.js component used to manage the parameters.

    Create a new file in ppc_robot_web/assets/js/TaskTypes/<Platform>/ named <TypeName>.vue (please note the CamelCase naming convention used in JavaScript):

    <template>
        <div class="task-type-editor main-content">
            <h2>{{ pgettext('title', 'Report Settings') }}</h2>
    
            <!-- Your UI template. -->
        </div>
    </template>
    
    <script>
        import Vue from "vue";
        import Component from "vue-class-component";
        import {ReportEditorStore} from "../../Stores/ReportEditorStore";
    
        @Component({
            props: {
                parameters: Object,
                store: ReportEditorStore,
                defaultParameters: Object,
                validation: Object,
            },
        })
        export default class UrlCheckerReport extends Vue {
            getValidations() {
                return {
                    // Define your parameter validation here.
                    // See https://monterail.github.io/vuelidate/
                };
            }
        }
    </script>
    

    The component will receive 4 parameters:

    • parameters: parameters object, this is the dictionary that is passed to create_steps.

    • store: instance of ReportEditorStore which contains the parameters. If you set its allowContinue property to false, user will not be able to save the parameters.

    • defaultParameters: default parameters for the given report type (as returned by the get_default_parameters() method). Useful if your report consists of multiple tables that can be configured by user โ€“ you can simply create a new table by coping the default one.

    • validation: validation result. See documentation for the Vuelidate library.

    Additionally, the editor has one method: getValidations(). This method should return the validation schema that is used to validate the parameters โ€“ see documentation for the Vuelidate library for more details. Additionally, AdWords/AdExtensionReport.vue is a nice example of validation in action.

  4. One last change to make! In ppc_robot_web/assets/js/TaskTypes/editors.js, add your component

    to the EDITOR_MAP (it is a nested object, so keep the structure):

    export const EDITOR_MAP = {
        // ...
        'adwords': {
            'type_name': d(require('./AdWords/TypeName.vue')),
        }
    };