Skip to content

Shipping Port Documentation

Overview

The Shipping Port module (ship.port) maintains a registry of ports used for international shipping operations. This master data model links ports to countries for logistics tracking and planning.


Model Information

Model Name: ship.port
Display Name: Shipping Port
Key Fields: None

Features

  • ❌ No audit logging
  • ❌ No multi-company support
  • ❌ No full-text search
  • ❌ No unique constraints

Key Fields Reference

Header Fields

Field Type Required Description
name Char Port name
country_id Many2One Country location

Default Order: Ordered by name alphabetically


API Methods

1. Create Port

Method: create(vals, context)

Creates a new shipping port record.

Parameters:

vals = {
    "name": str,           # Required: Port name
    "country_id": int,     # Optional: Country ID
}

Returns: int - New record ID

Example:

# Create port with country
port_id = get_model("ship.port").create({
    "name": "Port of Los Angeles",
    "country_id": usa_id
})

# Create port without country
port_id = get_model("ship.port").create({
    "name": "Port of Singapore"
})


2. Search Ports

Method: search_browse(condition, context)

Search ports by name or country.

Example:

# Search by name
ports = get_model("ship.port").search_browse([
    ["name", "ilike", "singapore"]
])

# Search by country
us_ports = get_model("ship.port").search_browse([
    ["country_id", "=", usa_id]
])

# Get all ports
all_ports = get_model("ship.port").search_browse([])


Common Use Cases

Use Case 1: Register Major International Ports

# Register world's busiest ports
ports = [
    {"name": "Port of Shanghai", "country_id": china_id},
    {"name": "Port of Singapore", "country_id": singapore_id},
    {"name": "Port of Ningbo-Zhoushan", "country_id": china_id},
    {"name": "Port of Shenzhen", "country_id": china_id},
    {"name": "Port of Guangzhou", "country_id": china_id},
    {"name": "Port of Busan", "country_id": south_korea_id},
    {"name": "Port of Hong Kong", "country_id": hong_kong_id},
    {"name": "Port of Qingdao", "country_id": china_id},
    {"name": "Port of Los Angeles", "country_id": usa_id},
    {"name": "Port of Rotterdam", "country_id": netherlands_id}
]

port_ids = []
for port_data in ports:
    port_id = get_model("ship.port").create(port_data)
    port_ids.append(port_id)
    print(f"Created: {port_data['name']}")

print(f"\nRegistered {len(port_ids)} shipping ports")

Use Case 2: List Ports by Region

# Get all Asian ports
asian_countries = [china_id, singapore_id, japan_id, south_korea_id, thailand_id]

asian_ports = get_model("ship.port").search_browse([
    ["country_id", "in", asian_countries]
])

print("Asian Shipping Ports:")
for port in asian_ports:
    print(f"- {port.name} ({port.country_id.name})")

Use Case 3: Setup Regional Port Groups

def setup_regional_ports(region_name, port_list):
    """
    Setup ports for a specific region

    Args:
        region_name: Name of the region
        port_list: List of (port_name, country_id) tuples

    Returns:
        List of created port IDs
    """
    print(f"Setting up {region_name} ports...")

    port_ids = []
    for port_name, country_id in port_list:
        # Check if port exists
        existing = get_model("ship.port").search([
            ["name", "=", port_name]
        ])

        if existing:
            print(f"  ✓ {port_name} (already exists)")
            port_ids.append(existing[0])
        else:
            port_id = get_model("ship.port").create({
                "name": port_name,
                "country_id": country_id
            })
            port_ids.append(port_id)
            print(f"  + {port_name} (created)")

    return port_ids

# Usage
north_america_ports = [
    ("Port of Los Angeles", usa_id),
    ("Port of Long Beach", usa_id),
    ("Port of New York/New Jersey", usa_id),
    ("Port of Savannah", usa_id),
    ("Port of Vancouver", canada_id),
    ("Port of Prince Rupert", canada_id)
]

na_port_ids = setup_regional_ports("North America", north_america_ports)

Use Case 4: Update Port Information

# Update port name or country
port_id = 1

get_model("ship.port").write([port_id], {
    "name": "Port of Los Angeles (POLA)",
    "country_id": usa_id
})

Search Functions

Search by Name Pattern

# Case-insensitive partial match
condition = [["name", "ilike", "%angeles%"]]
results = get_model("ship.port").search_browse(condition)

Search by Country

# Exact country match
condition = [["country_id", "=", usa_id]]
results = get_model("ship.port").search_browse(condition)

Search Ports Without Country

# Find ports missing country assignment
condition = [["country_id", "=", False]]
results = get_model("ship.port").search_browse(condition)

Model Relationship Description
country Many2One Port location country
sale.order Referenced by Orders may specify port
purchase.order Referenced by Purchases may specify port
stock.picking Referenced by Pickings may track port

Best Practices

1. Use Standard Port Names

# Good: Official port names
get_model("ship.port").create({
    "name": "Port of Los Angeles",
    "country_id": usa_id
})

# Avoid: Abbreviations or informal names
get_model("ship.port").create({
    "name": "LA Port"  # Unclear, not standard
})

2. Always Assign Country

# Good: Include country for geographic clarity
get_model("ship.port").create({
    "name": "Port of Shanghai",
    "country_id": china_id
})

# Bad: No country makes logistics unclear
get_model("ship.port").create({
    "name": "Port of Shanghai"
    # Missing country_id
})

3. Check for Duplicates

# Good: Check before creating
def create_or_get_port(name, country_id):
    # Check by name
    existing = get_model("ship.port").search([
        ["name", "=", name]
    ])

    if existing:
        return existing[0]

    # Create new
    return get_model("ship.port").create({
        "name": name,
        "country_id": country_id
    })

# Usage
port_id = create_or_get_port("Port of Singapore", singapore_id)

Performance Tips

1. Cache Port Lists

# Good: Cache commonly used port lists
_port_cache = {}

def get_ports_by_country(country_id):
    if country_id not in _port_cache:
        ports = get_model("ship.port").search_browse([
            ["country_id", "=", country_id]
        ])
        _port_cache[country_id] = ports
    return _port_cache[country_id]

# Usage
us_ports = get_ports_by_country(usa_id)

2. Bulk Load for Dropdowns

# Good: Load all ports once for selection lists
all_ports = get_model("ship.port").search_browse([])
port_options = [(p.id, p.name, p.country_id.name) for p in all_ports]

# Use cached list for multiple operations

Troubleshooting

"Port not found"

Cause: Port record doesn't exist
Solution: Create port record first

# Check if port exists
port_name = "Port of Shanghai"
existing = get_model("ship.port").search([
    ["name", "=", port_name]
])

if not existing:
    print(f"Port '{port_name}' not found. Creating...")
    get_model("ship.port").create({
        "name": port_name,
        "country_id": china_id
    })

"Multiple ports with same name"

Cause: No unique constraint on name field
Solution: Use name + country combination for uniqueness

# Check for duplicates
name = "Port of Victoria"
duplicates = get_model("ship.port").search([
    ["name", "=", name]
])

if len(duplicates) > 1:
    print(f"Found {len(duplicates)} ports named '{name}':")
    for port_id in duplicates:
        port = get_model("ship.port").browse(port_id)
        print(f"  - ID {port.id}: {port.country_id.name if port.country_id else 'No country'}")

Testing Examples

Unit Test: Create and Retrieve Port

def test_port_crud():
    # Create port
    port_id = get_model("ship.port").create({
        "name": "Test Port",
        "country_id": usa_id
    })

    # Verify creation
    assert port_id is not None

    # Read back
    port = get_model("ship.port").browse(port_id)
    assert port.name == "Test Port"
    assert port.country_id.id == usa_id

    # Update
    get_model("ship.port").write([port_id], {
        "name": "Updated Test Port"
    })

    # Verify update
    port = get_model("ship.port").browse(port_id)
    assert port.name == "Updated Test Port"

    # Delete
    get_model("ship.port").delete([port_id])

Security Considerations

Permission Model

  • View: Users with logistics/shipping access
  • Create/Modify: Admin or logistics manager
  • Delete: Admin only

Data Access

  • Public reference data
  • No sensitive information
  • No multi-company isolation needed

Version History

Last Updated: October 2025
Model File: ship_port.py
Framework: Netforce


Additional Resources

  • Port Destination Documentation: port.destination
  • Port Loading Documentation: port.loading
  • Country Documentation: country

This documentation is generated for developer onboarding and reference purposes.