======
Models
======

Listing
-------

.. note::
    The listing model can be returned as "short" listing. The "short" listing
    is the base data plus phone numbers, but excluding all other additional elements.

Legend
~~~~~~

Base
    Listing model without additional elements, except phone numbers
REQ
    Fields which are REQUIRED for update/create requests

.. list-table::
   :header-rows: 1
   :widths: 20 5 5 60

   * - Name
     - Base
     - REQ
     - Description
   * - id
     - Yes
     - No
     - The Opendi ID for this listing. The ID will be returned by Opendi, there is no need to include it for update/create requests.
   * - source_id
     - Yes
     - Yes
     - Partner's internal unique ID which identifies the listing in the partner's system.
   * - source_partner
     - Yes
     - No
     - Shows the owner of the listing. Value is "opendi", if it is not claimed. It is the name of the requestor, if it is claimed by the requestor. It is "other" when it cannot be claimed.
   * - claimed
     - Yes
     - No
     - If yes, it is already claimed by a partner. If no, it is free for claiming. This field cannot be set by a partner and will be ignored.
   * - name
     - Yes
     - Yes
     - The name of the listing
   * - address
     - Yes
     - Yes
     - The street name and number
   * - zip
     - Yes
     - Yes
     - Postal/ZIP code
   * - place
     - Yes
     - Yes
     - City
   * - show_address
     - No
     - No
     - true/false to indicate if the address is visible to the public. Defaults to true.
   * - country_code
     - Yes
     - Yes
     - Country code
   * - latitude
     - Yes
     - No
     - Latitude
   * - longitude
     - Yes
     - No
     - Longitude
   * - keywords
     - No
     - No
     - An array of keywords
   * - description
     - No
     - No
     - Informational text describing the business.
   * - emails
     - No
     - No
     - List of Email elements
   * - phone
     - Yes
     - No
     - List of Phone elements
   * - url
     - Yes
     - No
     - Full URL at which the listing can be viewed
   * - hours
     - No
     - No
     - Element of type Opening Hours.
   * - images
     - No
     - No
     - Element of type Image. Will be ignored in update/create requests.
   * - links
     - No
     - No
     - List of Links
   * - categories
     - No
     - No
     - A list of Category models.
   * - active
     - No
     - No
     - Set to false when the listing is suppressed, and true when it is not.
       Populated by Opendi.
   * - contact
     - No
     - No
     - Contact person of type Person. Usually the person responsible for this listing. The partners contact data will be used if omitted.

Example
~~~~~~~

If you request a listing by issuing: **GET /de/listings/6433484**

You might get the following result:

.. code-block:: javascript

    {
        "id": "6433484",
        "source_id": "123456",
        "source_partner": "other",
        "name": "Opendi AG",
        "address": "40 Müllerstr.",
        "zip": "80469",
        "place": "München",
        "country_code": "DE",
        "latitude": 48.1312973,
        "longitude": 11.5699438,
        "keywords": [
            "Contacts",
            "White Pages",
            "Yellow Pages",
            "Telephonenumbers",
            "Nice People"
        ],
        "description": "A company full of nice people creating internet based white pages and and yellow pages.",
        "emails": [
            {
                "id": "2137356",
                "address": "a.stahl@opendi.com"
            }
        ],
        "phones": [
            {
                "id": "10297929",
                "type": "landline",
                "number": "+498001055105"
            },
            {
                "id": "10297930",
                "type": "landline",
                "number": "+4989189476620"
            },
            {
                "id": "10297931",
                "type": "fax",
                "number": "+4989189476626"
            }
        ],
        "url": "http://muenchen.de-eu-staging.opendi.com/6433484.html",
        "hours": {
            "monday": [
                {
                    "start": "09:00:00",
                    "end": "17:00:00"
                }
            ],
            "tuesday": [
                {
                    "start": "09:00:00",
                    "end": "17:00:00"
                }
            ],
            "wednesday": [
                {
                    "start": "09:00:00",
                    "end": "17:00:00"
                }
            ],
            "thursday": [
                {
                    "start": "09:00:00",
                    "end": "17:00:00"
                }
            ],
            "friday": [
                {
                    "start": "10:00:00",
                    "end": "12:00:00"
                },
                {
                    "start": "14:00:00",
                    "end": "17:00:00"
                }
            ],
            "saturday": [],
            "sunday": []
        },
        "images": [
            {
                "id": "1591",
                "type": "logo",
                "url": "http://static.opendi.com/yellow/local/de/6433484/images/1591.jpg",
                "base64": null,
                "caption": "Opendi logo"
            }
        ],
        "links": [
            {
                "id": "2137357",
                "type": "website",
                "url": "www.stadtbranchenbuch.com",
                "display": "Stadt Branchenbuch"
            },
            {
                "id": "2137358",
                "type": "googleplus",
                "url": "https://plus.google.com/118150864364347134043/",
                "display": "https://plus.google.com/118150864364347134043/"
            }
        ],
        "categories": [
            {
                "id": "58",
                "name": "Bestatter"
            }
        ],
        "active": true,
        "contact": {
            "id": "255846",
            "name": "Christian",
            "surname": "Grobmeier",
            "title": "Sir",
            "gender": "M"
        }
    }


Person
------

A person.

========= ====== ========================================= ===============
 Name      Req?   Description                               Example
========= ====== ========================================= ===============
 id        No     Unique Person ID, populated by Opendi.    123
 name      Yes    The name of the person                    Christian
 surname   Yes    The surname of the person                 Grobmeier
 title     No     A title the person holds                  Dr., Engineer
 gender    No     The gender, used for correct salutation   M, F, U
========= ====== ========================================= ===============

Possible Gender types:

====== =====================
 Type   Description
====== =====================
 M      Male
 F      Female
 U      Unknown, Undefined
====== =====================

Phone
-----

A public phone contact.

======== ====== ======================================= ===========
 Name     Req?   Description                             Example
======== ====== ======================================= ===========
 id       No     Unique phone ID, populated by Opendi.   123
 type     Yes    Phone type as stated below              mobile
 number   Yes    Phone number in E.164 format            +49123456
 label    No     Freetext describing this number         Secretary
======== ====== ======================================= ===========

Possible Phone types:

========== ====================
 Type       Description
========== ====================
 landline   Landline number
 mobile     Mobile number
 fax        Fax number
 tollfree   Toll free number
========== ====================

Email
-----

An Email contact.

========= ====== ======================================= =================
 Name      Req?   Description                             Example
========= ====== ======================================= =================
 id        No     Unique email ID, populated by Opendi.   123
 address   Yes    Email address                           info@opendi.com
========= ====== ======================================= =================

Opening Hours
-------------

Opening hours of this business.

Each day may have multiple intervals when the business is open. This allows for
breaks in the opening hours.

Opening hours are send in the ISO 8601 format. The format allows the time to become
24:00, when the end of the day is meant. In example, a listing opened for 24 hours
has the opening time 00:00 - 24:00.

A listing having the time 00:00 - 00:00 would mean it is not open at all.

It is not supported to send day spanning intervals. In example, MO 14:00 - 02:00 would
not be accepted as the end time is before the start time. Supporting such formats
would lead to several issues, like there is no way to tell if 02:00 would be actually
tuesday or not wednesday. Also, the 02:00 could by a mistake where the sender
mixed up start and end time. Finally we cannot say for sure if 00:00 to 00:00 is
not actually meaning the shop is closed.

A time span from MO 15:00 - 02:00 (tuesday) needs to be send as an interval of
MO 15:00 - 24:00 and TU 00:00 - 02:00.

============ ====== ========================================== =================
 Name         Req?   Description                                Example
============ ====== ========================================== =================
 monday       No     A list of Opening Hours Interval models.
 tuesday      No     A list of Opening Hours Interval models.
 wednesday    No     A list of Opening Hours Interval models.
 thursday     No     A list of Opening Hours Interval models.
 friday       No     A list of Opening Hours Interval models.
 saturday     No     A list of Opening Hours Interval models.
 sunday       No     A list of Opening Hours Interval models.
 text         No     Text with additional opening hours info.   By appointment.
============ ====== ========================================== =================

At least one day, or the ``text`` field should be set when specifying this
element.

Example including Intervals:

.. code-block:: javascript

    {
        "monday": [
            {
                "start": "10:00",
                "end": "11:00"
            },
            {
                "start": "14:00",
                "end": "15:00"
            }
        ],
        "tuesday": [
            {
                "start": "10:00",
                "end": "11:00"
            },
            {
                "start": "14:00",
                "end": "15:00"
            }
        ],
        "text": "We also work by appointment. Call us to schedule."
    }


Opening Hour Interval
---------------------

Interval within the day for opening hours. Uses ISO 8601 time format (`hh:mm` or
`hh:mm:ss`).

.. list-table::
   :header-rows: 1

   * - Name
     - Req?
     - Description
     - Example
   * - start
     - Yes
     - Start of the interval
     - 10:00
   * - end
     - Yes
     - Ending of the interval
     - 11:00


Offer
-----

A special offer from the listings owner. In example, a promotional message
with an optional URL.

============= ====== =========================================== ===============
 Name          Req?   Description                                 Example
============= ====== =========================================== ===============
 message       Yes    A promotional message                       Today 50% off
 url           No     A protocol prefixed url
============= ====== =========================================== ===============

Example:

.. code-block:: javascript

    {
        "message": "Today 50% off to each Pizza",
        "url": "http://www.example.com/specialoffer"
    }

Image
-----

An image representing the listing.

Opendi will generate thumbnails and resized versions from uploaded images.

Currently the maximum image size used is 1200x1200px. This is matter
to change without prior warning. The maximum upload payload is 4 MB.

When uploading an image, populate the **base64** field with Base 64 encoded
image data. This field will not be populated when retrieving an image.

======= ====== ======================================= ============
 Name    Req?   Description                             Example
======= ====== ======================================= ============
id       No     Unique image ID, populated by Opendi    123
type     Yes    Type of image, see list below           logo
url      No     Image URL, populated by Opendi
base64   Yes    Base64 encoded image data
caption  No     Caption for this image                  Cool image
======= ====== ======================================= ============

Possible image types:

========== ========================
 Type       Description
========== ========================
 logo       Business logo
 gallery    A gallery image
 printad    A printed advertisment
========== ========================

An example with base64 encoded image data:

.. code-block:: javascript

    {
        "type": "logo"
        "base64": "VGhpcyBpcyBwcmV0ZW5kaW5nIHRvIGJlIGFuIGltYWdlLg=="
    }

An example for requesting an already created image:

.. code-block:: javascript

    {
        "id": "15662346676"
        "type": "logo"
        "url": "http://static.opendi.com/images/hello.jpg"
    }

Review
------

A customer review.

============ ====== ======================================= ===========================
 Name         Req?   Description                             Example
============ ====== ======================================= ===========================
id            No     Unique review ID, populated by Opendi   123
source_id     Yes    Partner's internal unique review ID     321
reviewer      Yes    Name of the person writing the review   John Doe
reviewed      No     Name of the reviewed entity, used when  Pizzeria
                     there are several entities within the
                     same listing.
title         Yes    The review title                        Great pizza!
text          No     Full review text
rating        Yes    Review rating, 1-5 where 5 is best      3
review_url
listing_url

date_time     No     The date and time when the review was   2015-02-16T17:38:56+02:00
                     given (defaults to current datetime)
============ ====== ======================================= ===========================

The datetime format used in ``date_time`` is defined in `RFC3339`_, section 5.6.
It should contain the full date, time and timezone.

.. _RFC3339: https://www.ietf.org/rfc/rfc3339.txt

Link
----

A link to a web page.

======= ====== ======================================= ====================
 Name    Req?   Description                             Example
======= ====== ======================================= ====================
id       No     Unique link ID, populated by Opendi     123
type     Yes    Type of Link, see list below            website
url      Yes    The full URL to the webpage             http://opendi.com
display  No     The link text / title.                  Opendi homepage
======= ====== ======================================= ====================

Allowed Link types:

============== =================================================================================
 Type           Description
============== ========================
facebook        Facebook
googleplus      Google plus
linkedin        Linkedin
menu            Restaurant menu page
order           Order page
reservations    Reservations page
twitter         Twitter
website         Web site
xing            Xing
video           Video: An actual video, in example: https://www.youtube.com/watch?v=Ep__vi4Dvf0
youtube         A YouTube channel, in example: https://www.youtube.com/user/TheApacheFoundation
============== =================================================================================

Example:

.. code-block:: javascript

    {
        "type": "facebook",
        "url": "http://www.facebook.de/opendiAG",
        "display": "Opendi facebook page"
    }

Category
--------

A listing category.

.. list-table::
   :header-rows: 1

   * - Name
     - Req?
     - Description
   * - id
     - Yes
     - Unique ID of the category
   * - name
     - Yes
     - Name of the category

Example:

.. code-block:: javascript

    {
        "id": "50",
        "name": "Window Cleaners"
    }

Mapping
-------

A mapping between a Partner's listing ID and Opendi's listing ID.

============= ====== =========================================== ===============
 Name          Req?   Description                                 Example
============= ====== =========================================== ===============
 source_id     Yes    Partner's unique ID.                        12345
 opendi_id     Yes    Corresponding Opendi's unique listing ID.   54321
============= ====== =========================================== ===============

Partner provides a source_id when creating a listing.

Example:

.. code-block:: javascript

    {
        "source_id": "12345",
        "opendi_id": "54321"
    }

Error
-----

Returned in case of an error.

.. list-table::
   :header-rows: 1

   * - Name
     - Req?
     - Description
   * - type
     - Yes
     - The error type, see below
   * - message
     - Yes
     - Human readable error message
   * - details
     - No
     - An additional array of errors, e.g. validation errors

Possible error types:

.. list-table::
   :header-rows: 1

   * - Name
     - Description
   * - bad_request
     - Your request contained an error.
   * - blacklist
     - Trying to modify a blacklisted listing
   * - internal
     - An unspecified internal error occurred. Please contact support.
   * - validation
     - Model validation failed.

Example:

.. code-block:: javascript

    {
        "type": "validation",
        "message": "Validation failed for Listing model",
        "details": [
            "'id' field must be an integer, string given",
            "'zip' field must be numeric"
        ]
    }