Add GAN samples.
Reviewed in http://codereview.appspot.com/4867056/ Index: samples/gan/ccoffers/offers.py =================================================================== new file mode 100644
This commit is contained in:
126
samples/gan/ccoffers/offers.py
Normal file
126
samples/gan/ccoffers/offers.py
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
#!/usr/bin/python2.4
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# Copyright (C) 2011 Google Inc.
|
||||||
|
|
||||||
|
"""Sample for retrieving credit-card offers from GAN."""
|
||||||
|
|
||||||
|
__author__ = 'leadpipe@google.com (Luke Blanshard)'
|
||||||
|
|
||||||
|
import gflags
|
||||||
|
import httplib2
|
||||||
|
import json
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
import stat
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from django.template import Template, Context
|
||||||
|
from django.template.loader import get_template
|
||||||
|
|
||||||
|
from apiclient.discovery import build
|
||||||
|
from oauth2client.file import Storage
|
||||||
|
from oauth2client.client import OAuth2WebServerFlow
|
||||||
|
from oauth2client.tools import run
|
||||||
|
|
||||||
|
settings.configure(DEBUG=True, TEMPLATE_DEBUG=True,
|
||||||
|
TEMPLATE_DIRS=('.'))
|
||||||
|
|
||||||
|
|
||||||
|
FLAGS = gflags.FLAGS
|
||||||
|
|
||||||
|
# Set up a Flow object to be used if we need to authenticate. This
|
||||||
|
# sample uses OAuth 2.0, and we set up the OAuth2WebServerFlow with
|
||||||
|
# the information it needs to authenticate. Note that it is called
|
||||||
|
# the Web Server Flow, but it can also handle the flow for native
|
||||||
|
# applications <http://code.google.com/apis/accounts/docs/OAuth2.html#IA>
|
||||||
|
# The client_id client_secret are copied from the API Access tab on
|
||||||
|
# the Google APIs Console <http://code.google.com/apis/console>. When
|
||||||
|
# creating credentials for this application be sure to choose an Application
|
||||||
|
# type of "Installed application".
|
||||||
|
FLOW = OAuth2WebServerFlow(
|
||||||
|
client_id='767567128246-ti2q06i1neqm5boe2m1pqdc2riivhk41.apps.googleusercontent.com',
|
||||||
|
client_secret='UtdXI8nKD2SEcQRLQDZPkGT9',
|
||||||
|
scope='https://www.googleapis.com/auth/gan.readonly',
|
||||||
|
user_agent='gan-ccoffers-sample/1.0')
|
||||||
|
|
||||||
|
# The gflags module makes defining command-line options easy for
|
||||||
|
# applications. Run this program with the '--help' argument to see
|
||||||
|
# all the flags that it understands.
|
||||||
|
gflags.DEFINE_enum('logging_level', 'DEBUG',
|
||||||
|
['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'],
|
||||||
|
'Set the level of logging detail.')
|
||||||
|
|
||||||
|
gflags.DEFINE_enum("output_type", 'STDOUT', ['BOTH', 'HTML', 'STDOUT'],
|
||||||
|
'Set how to output the results received from the API')
|
||||||
|
|
||||||
|
gflags.DEFINE_string('credentials_filename', 'offers.dat',
|
||||||
|
'File to store credentials in', short_name='cf')
|
||||||
|
|
||||||
|
gflags.DEFINE_multistring('advertiser', None,
|
||||||
|
'If given, advertiser we should run as')
|
||||||
|
|
||||||
|
|
||||||
|
def usage(argv):
|
||||||
|
print 'Usage: %s <publisher-id>\n%s' % (argv[0], FLAGS)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
def main(argv):
|
||||||
|
# Let the gflags module process the command-line arguments
|
||||||
|
try:
|
||||||
|
argv = FLAGS(argv)
|
||||||
|
except gflags.FlagsError, e:
|
||||||
|
raise e
|
||||||
|
usage(argv)
|
||||||
|
|
||||||
|
if len(argv) != 2:
|
||||||
|
usage(argv)
|
||||||
|
publisher = argv[1]
|
||||||
|
|
||||||
|
# Set the logging according to the command-line flag
|
||||||
|
logging.getLogger().setLevel(getattr(logging, FLAGS.logging_level))
|
||||||
|
|
||||||
|
# If the Credentials don't exist or are invalid run through the native client
|
||||||
|
# flow. The Storage object will ensure that if successful the good
|
||||||
|
# Credentials will get written back to a file.
|
||||||
|
storage = Storage(FLAGS.credentials_filename)
|
||||||
|
credentials = storage.get()
|
||||||
|
if credentials is None or credentials.invalid:
|
||||||
|
credentials = run(FLOW, storage)
|
||||||
|
|
||||||
|
# Create an httplib2.Http object to handle our HTTP requests and authorize it
|
||||||
|
# with our good Credentials.
|
||||||
|
http = httplib2.Http()
|
||||||
|
http = credentials.authorize(http)
|
||||||
|
|
||||||
|
service = build('gan', 'v1beta1', http=http)
|
||||||
|
|
||||||
|
ccOffers = service.ccOffers()
|
||||||
|
|
||||||
|
# Retrieve the relevant offers.
|
||||||
|
list_call = ccOffers.list(publisher=publisher,
|
||||||
|
# TODO(leadpipe): add back when advertiser is repeated
|
||||||
|
# advertiser=FLAGS.advertiser,
|
||||||
|
projection='full')
|
||||||
|
list = list_call.execute()
|
||||||
|
list['publisher'] = publisher
|
||||||
|
|
||||||
|
if FLAGS.output_type in ["BOTH", "HTML"]:
|
||||||
|
template = get_template('offers_template.html')
|
||||||
|
context = Context(list)
|
||||||
|
|
||||||
|
fname = '%s.html' % publisher
|
||||||
|
out = open(fname, 'w')
|
||||||
|
out.write(template.render(context).encode('UTF-8'))
|
||||||
|
os.fchmod(out.fileno(), stat.S_IROTH|stat.S_IRGRP|stat.S_IRUSR|stat.S_IWUSR)
|
||||||
|
out.close()
|
||||||
|
|
||||||
|
print 'Wrote %s' % fname
|
||||||
|
|
||||||
|
if FLAGS.output_type in ["BOTH", "STDOUT"]:
|
||||||
|
print json.dumps(list, sort_keys=True, indent=4)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main(sys.argv)
|
||||||
99
samples/gan/ccoffers/offers_template.html
Normal file
99
samples/gan/ccoffers/offers_template.html
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Credit Card Offers for Publisher {{ publisher }}</title>
|
||||||
|
<style>
|
||||||
|
h2 {
|
||||||
|
margin: 3ex 0 1ex;
|
||||||
|
}
|
||||||
|
td.cardName {
|
||||||
|
padding-bottom: 2ex;
|
||||||
|
}
|
||||||
|
td {
|
||||||
|
vertical-align: top;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
tr.details td {
|
||||||
|
padding: 0 3ex;
|
||||||
|
}
|
||||||
|
td pre {
|
||||||
|
margin: 3ex 3em;
|
||||||
|
width: 500px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script>
|
||||||
|
function toggleDisplay(id) {
|
||||||
|
el = document.getElementById(id);
|
||||||
|
if (el.style.display == "none") {
|
||||||
|
el.style.display = "block"
|
||||||
|
} else {
|
||||||
|
el.style.display = "none"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Credit Card Offers for Publisher {{ publisher }}</h1>
|
||||||
|
<table>
|
||||||
|
{% for item in items %}
|
||||||
|
<tr>
|
||||||
|
<td colspan=3 class="cardName">
|
||||||
|
<h2>{{ item.cardName }}</h2>
|
||||||
|
{{ item.network }} from {{ item.issuer }} - <a href="{{ item.trackingUrl }}">Click to apply</a>
|
||||||
|
- <a href="javascript:toggleDisplay('pre{{forloop.counter}}');">debug</a>
|
||||||
|
<tr class="details">
|
||||||
|
<td>
|
||||||
|
{% if item.imageUrl %}
|
||||||
|
<img src="{{ item.imageUrl }}" title="Image from GAN" />
|
||||||
|
{% endif %}
|
||||||
|
{% if item.logoUrl %}
|
||||||
|
<img src="{{ item.logoUrl }}" title="Image from AdConnect" />
|
||||||
|
{% endif %}
|
||||||
|
{% if item.disclaimer %}
|
||||||
|
<div>{{ item.disclaimer }}</div>
|
||||||
|
{% endif %}
|
||||||
|
<td>
|
||||||
|
<div>APR: {{ item.aprDisplay }}</div>
|
||||||
|
<div>Annual Fee: {{ item.annualFeeDisplay }}</div>
|
||||||
|
<div>Grace Period: {{ item.gracePeriodDisplay }}</div>
|
||||||
|
<div>Late Payment Fee: {{ item.latePaymentFee }}</div>
|
||||||
|
<div>Credit Rating: {{ item.creditRatingDisplay }}</div>
|
||||||
|
<td>
|
||||||
|
{% if item.introAprDisplay %}
|
||||||
|
<div>Intro APR: {{ item.introAprDisplay }}</div>
|
||||||
|
{% endif %}
|
||||||
|
{% if item.balanceTransferAprDisplay %}
|
||||||
|
<div>Balance Transfer APR: {{ item.balanceTransferAprDisplay }}</div>
|
||||||
|
{% endif %}
|
||||||
|
{% if item.balanceTransferFeeDisplay %}
|
||||||
|
<div>Balance Transfer Fee: {{ item.balanceTransferFeeDisplay }}</div>
|
||||||
|
{% endif %}
|
||||||
|
{% if item.cashAdvanceAprDisplay %}
|
||||||
|
<div>Cash Advance APR: {{ item.cashAdvanceAprDisplay }}</div>
|
||||||
|
{% endif %}
|
||||||
|
{% if item.cashAdvanceFeeDisplay %}
|
||||||
|
<div>Cash Advance Fee: {{ item.cashAdvanceFeeDisplay }}</div>
|
||||||
|
{% endif %}
|
||||||
|
<!--
|
||||||
|
<td>
|
||||||
|
Card benefits: <ul>
|
||||||
|
{% for benefit in item.cardBenefits %}
|
||||||
|
<li> {{ benefit }} </li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
<td>
|
||||||
|
Additional benefits: <ul>
|
||||||
|
{% for benefit in item.additionalCardBenefits %}
|
||||||
|
<li> {{ benefit }} </li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
-->
|
||||||
|
</tr>
|
||||||
|
<tr><td colspan=3><pre id="pre{{forloop.counter}}" style="display:none">
|
||||||
|
{{ item|pprint|linebreaks }}</pre>
|
||||||
|
{% empty %}
|
||||||
|
<tr><td>
|
||||||
|
<h2>Whoops, {{ publisher }} has no associated credit card offers.</h2>
|
||||||
|
{% endfor %}
|
||||||
|
</table>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
170
samples/gan/events/events.py
Normal file
170
samples/gan/events/events.py
Normal file
@@ -0,0 +1,170 @@
|
|||||||
|
#!/usr/bin/python2.4
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# Copyright (C) 2011 Google Inc.
|
||||||
|
|
||||||
|
"""Sample for retrieving credit-card offers from GAN."""
|
||||||
|
|
||||||
|
__author__ = 'leadpipe@google.com (Luke Blanshard)'
|
||||||
|
|
||||||
|
import apiclient
|
||||||
|
import gflags
|
||||||
|
import httplib2
|
||||||
|
import json
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
import stat
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from django.template import Template, Context
|
||||||
|
from django.template.loader import get_template
|
||||||
|
|
||||||
|
from apiclient.discovery import build
|
||||||
|
from oauth2client.file import Storage
|
||||||
|
from oauth2client.client import OAuth2WebServerFlow
|
||||||
|
from oauth2client.tools import run
|
||||||
|
|
||||||
|
settings.configure(DEBUG=True, TEMPLATE_DEBUG=True,
|
||||||
|
TEMPLATE_DIRS=('.'))
|
||||||
|
|
||||||
|
|
||||||
|
FLAGS = gflags.FLAGS
|
||||||
|
|
||||||
|
# Set up a Flow object to be used if we need to authenticate. This
|
||||||
|
# sample uses OAuth 2.0, and we set up the OAuth2WebServerFlow with
|
||||||
|
# the information it needs to authenticate. Note that it is called
|
||||||
|
# the Web Server Flow, but it can also handle the flow for native
|
||||||
|
# applications <http://code.google.com/apis/accounts/docs/OAuth2.html#IA>
|
||||||
|
# The client_id client_secret are copied from the API Access tab on
|
||||||
|
# the Google APIs Console <http://code.google.com/apis/console>. When
|
||||||
|
# creating credentials for this application be sure to choose an Application
|
||||||
|
# type of "Installed application".
|
||||||
|
FLOW = OAuth2WebServerFlow(
|
||||||
|
client_id='767567128246-ti2q06i1neqm5boe2m1pqdc2riivhk41.apps.googleusercontent.com',
|
||||||
|
client_secret='UtdXI8nKD2SEcQRLQDZPkGT9',
|
||||||
|
scope='https://www.googleapis.com/auth/gan.readonly',
|
||||||
|
user_agent='gan-events-sample/1.0')
|
||||||
|
|
||||||
|
# The gflags module makes defining command-line options easy for
|
||||||
|
# applications. Run this program with the '--help' argument to see
|
||||||
|
# all the flags that it understands.
|
||||||
|
gflags.DEFINE_enum('logging_level', 'DEBUG',
|
||||||
|
['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'],
|
||||||
|
'Set the level of logging detail.')
|
||||||
|
|
||||||
|
gflags.DEFINE_enum("output_type", 'STDOUT', ['BOTH', 'HTML', 'STDOUT'],
|
||||||
|
'Set how to output the results received from the API')
|
||||||
|
|
||||||
|
gflags.DEFINE_string('credentials_filename', 'events.dat',
|
||||||
|
'File to store credentials in', short_name='cf')
|
||||||
|
|
||||||
|
API_FLAGS = {'eventDateMin':None, 'eventDateMax':None, 'advertiserId':None,
|
||||||
|
'publisherId':None, 'orderId':None, 'sku':None,
|
||||||
|
'productCategory':None, 'linkId':None, 'memberId':None,
|
||||||
|
'status':None, 'type':None, 'role':None, 'roleId':None}
|
||||||
|
|
||||||
|
gflags.DEFINE_string(
|
||||||
|
'eventDateMin', None,
|
||||||
|
'RFC 3339 formatted min date. Ex: 2005-08-09-T10:57:00-08:00')
|
||||||
|
|
||||||
|
gflags.DEFINE_string(
|
||||||
|
'eventDateMax', None,
|
||||||
|
'RFC 3339 formatted max date. Ex: 2005-08-09-T10:57:00-08:00')
|
||||||
|
|
||||||
|
gflags.DEFINE_string('advertiserId', None,
|
||||||
|
'caret delimited advertiser IDs')
|
||||||
|
|
||||||
|
gflags.DEFINE_string('publisherId', None,
|
||||||
|
'caret delimited publisher IDs')
|
||||||
|
|
||||||
|
gflags.DEFINE_string('orderId', None,
|
||||||
|
'caret delimited order IDs')
|
||||||
|
|
||||||
|
gflags.DEFINE_string('sku', None,
|
||||||
|
'caret delimited SKUs')
|
||||||
|
|
||||||
|
gflags.DEFINE_string('productCategory', None,
|
||||||
|
'caret delimited product categories')
|
||||||
|
|
||||||
|
gflags.DEFINE_string('linkId', None,
|
||||||
|
'caret delimited link IDs')
|
||||||
|
|
||||||
|
gflags.DEFINE_string('memberId', None,
|
||||||
|
'caret delimited member IDs')
|
||||||
|
|
||||||
|
gflags.DEFINE_string('status', None,
|
||||||
|
'status of events - valid values "active" or "cancelled"')
|
||||||
|
|
||||||
|
gflags.DEFINE_string('type', None,
|
||||||
|
'type of events - valid values "action" or "transaction"')
|
||||||
|
|
||||||
|
|
||||||
|
def usage(argv):
|
||||||
|
print 'Usage: %s <role> <role-id>\n%s' % (argv[0], FLAGS)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
def main(argv):
|
||||||
|
# Let the gflags module process the command-line arguments
|
||||||
|
try:
|
||||||
|
argv = FLAGS(argv)
|
||||||
|
except gflags.FlagsError, e:
|
||||||
|
print e
|
||||||
|
usage(argv)
|
||||||
|
|
||||||
|
if len(argv) != 3:
|
||||||
|
usage(argv)
|
||||||
|
params = {
|
||||||
|
'role': argv[1],
|
||||||
|
'roleId': argv[2]
|
||||||
|
}
|
||||||
|
|
||||||
|
# Set the logging according to the command-line flag
|
||||||
|
logging.getLogger().setLevel(getattr(logging, FLAGS.logging_level))
|
||||||
|
|
||||||
|
# If the Credentials don't exist or are invalid run through the native client
|
||||||
|
# flow. The Storage object will ensure that if successful the good
|
||||||
|
# Credentials will get written back to a file.
|
||||||
|
storage = Storage(FLAGS.credentials_filename)
|
||||||
|
credentials = storage.get()
|
||||||
|
if credentials is None or credentials.invalid:
|
||||||
|
credentials = run(FLOW, storage)
|
||||||
|
|
||||||
|
# Create an httplib2.Http object to handle our HTTP requests and authorize it
|
||||||
|
# with our good Credentials.
|
||||||
|
http = httplib2.Http()
|
||||||
|
http = credentials.authorize(http)
|
||||||
|
|
||||||
|
service = build('gan', 'v1beta1', http=http)
|
||||||
|
|
||||||
|
events = service.events()
|
||||||
|
|
||||||
|
# Filter out all params that aren't set.
|
||||||
|
for key in FLAGS:
|
||||||
|
if key in API_FLAGS and FLAGS[key].value != None:
|
||||||
|
params[key] = FLAGS[key].value
|
||||||
|
|
||||||
|
# Retrieve the relevant events.
|
||||||
|
try:
|
||||||
|
list_call = events.list(**params)
|
||||||
|
list = list_call.execute()
|
||||||
|
except apiclient.errors.HttpError, e:
|
||||||
|
print json.dumps(e.__dict__, sort_keys=True, indent=4)
|
||||||
|
|
||||||
|
if FLAGS.output_type in ["BOTH", "HTML"]:
|
||||||
|
template = get_template('events_template.html')
|
||||||
|
context = Context(list)
|
||||||
|
|
||||||
|
out = open("output.html", 'w')
|
||||||
|
out.write(template.render(context).encode('UTF-8'))
|
||||||
|
os.fchmod(out.fileno(), stat.S_IROTH|stat.S_IRGRP|stat.S_IRUSR|stat.S_IWUSR)
|
||||||
|
out.close()
|
||||||
|
|
||||||
|
print 'Wrote output.html'
|
||||||
|
|
||||||
|
if FLAGS.output_type in ["BOTH", "STDOUT"]:
|
||||||
|
print json.dumps(list, sort_keys=True, indent=4)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main(sys.argv)
|
||||||
106
samples/gan/events/events_template.html
Normal file
106
samples/gan/events/events_template.html
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Event Response</title>
|
||||||
|
<style>
|
||||||
|
h2 {
|
||||||
|
margin: 3ex 0 1ex;
|
||||||
|
}
|
||||||
|
th {
|
||||||
|
background-color: grey;
|
||||||
|
}
|
||||||
|
td {
|
||||||
|
vertical-align: top;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
tr.details td {
|
||||||
|
padding: 0 3ex;
|
||||||
|
}
|
||||||
|
td pre {
|
||||||
|
margin: 3ex 3em;
|
||||||
|
width: 500px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script>
|
||||||
|
function toggleDisplay(id) {
|
||||||
|
el = document.getElementById(id);
|
||||||
|
if (el.style.display == "none") {
|
||||||
|
el.style.display = "block"
|
||||||
|
} else {
|
||||||
|
el.style.display = "none"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Events</h1>
|
||||||
|
<table border="1" cellspacing="0">
|
||||||
|
{% for item in items %}
|
||||||
|
<tr>
|
||||||
|
<th>Event Date</th>
|
||||||
|
{% if item.modifyDate %}<th>Modify Date</th> {% endif %}
|
||||||
|
{% if item.advertiserId %}<th>Advertiser Id</th>{% endif %}
|
||||||
|
{% if item.advertiserName %}<th>Advertiser Name</th>{% endif %}
|
||||||
|
{% if item.publisherId %}<th>Publisher Id</th>{% endif %}
|
||||||
|
{% if item.publisherName %}<th>Publisher Name</th>{% endif %}
|
||||||
|
<th>Order Id</th>
|
||||||
|
<th>Member Id</th>
|
||||||
|
<th>Event Status</th>
|
||||||
|
<th>Event Type</th>
|
||||||
|
<th>Commissionable Sales</th>
|
||||||
|
{% if item.earnings %}<th>Earnings (Publisher Only)</th>{% endif %}
|
||||||
|
{% if item.publisherFee %}<th>Publisher Fee (Advertiser Only)</th>{% endif %}
|
||||||
|
{% if item.networkFee %}<th>Network Fee (Advertiser Only)</th>{% endif %}
|
||||||
|
<tr class="eventinfo">
|
||||||
|
<td>{{ item.eventDate }}</td>
|
||||||
|
{% if item.modifyDate %}<td>{{ item.modifyDate }}</td>{% endif %}
|
||||||
|
<td>{{ item.advertiserId }}{{ item.publisherId }}</td>
|
||||||
|
<td>{{ item.advertiserName }}{{ item.publisherName }}</td>
|
||||||
|
<td>{{ item.orderId }}</td>
|
||||||
|
<td>{{ item.memberId }}</td>
|
||||||
|
<td>{{ item.status }}</td>
|
||||||
|
<td>{{ item.type }}</td>
|
||||||
|
<td>{{ item.commissionableSales }}</td>
|
||||||
|
{% if item.earnings %}<td>{{ item.earnings }}</td> {% endif %}
|
||||||
|
{% if item.publisherFee %}<td>{{ item.publisherFee }}</td>{% endif %}
|
||||||
|
{% if item.networkFee %}<td>{{ item.networkFee }}</td>{% endif %}
|
||||||
|
</tr>
|
||||||
|
<tr style="border:1px solid #444">
|
||||||
|
<td class="products">Products:</td>
|
||||||
|
<td colspan="11">
|
||||||
|
<table border="1" cellspacing="0">
|
||||||
|
<tr>
|
||||||
|
<th>Sku</th>
|
||||||
|
<th>Sku Name</th>
|
||||||
|
<th>Unit Price</th>
|
||||||
|
<th>Category ID</th>
|
||||||
|
<th>Category Name</th>
|
||||||
|
<th>Quantity</th>
|
||||||
|
<th>Publisher Fee</th>
|
||||||
|
<th>Earnings</th>
|
||||||
|
<th>Network Fee</th>
|
||||||
|
</tr>
|
||||||
|
{% for product in item.products %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ product.sku }}</td>
|
||||||
|
<td>{{ product.skuName }}</td>
|
||||||
|
<td>{{ product.unitPrice }}</td>
|
||||||
|
<td>{{ product.categoryId }}</td>
|
||||||
|
<td>{{ product.categoryName }}</td>
|
||||||
|
<td>{{ product.quantity }}</td>
|
||||||
|
<td>{{ product.publisherFee }}</td>
|
||||||
|
<td>{{ product.earnings }}</td>
|
||||||
|
<td>{{ product.networkFee }}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</table>
|
||||||
|
</tr>
|
||||||
|
{% empty %}
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<p style="padding:10px">No events fit that criteria. Try searching for different timeframe.</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</table>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Reference in New Issue
Block a user