Cannot find plant assets from crop plan API

Hello,

I am experimenting on crop plans and hoping to programmatically create/add/edit crop plans through an API. Here is the screenshot of the crop plan I manually created from UI.

.

I can get the plan information by /api/plan/crop endpoint. However, when I requested details on a specific plan by api/plan/crop/{plan_uuid}, I could not see information about plant assets. The return from API is below

{
  "jsonapi": {
    "version": "1.0",
    "meta": {
      "links": {
        "self": {
          "href": "http://jsonapi.org/format/1.0/"
        }
      }
    }
  },
  "data": {
    "type": "plan--crop",
    "id": "fe394bee-07c1-4fb7-b4ea-46b673d9a283",
    "links": {
      "self": {
        "href": "http://axilab.ecn.purdue.edu/api/plan/crop/fe394bee-07c1-4fb7-b4ea-46b673d9a283?resourceVersion=id%3A6"
      }
    },
    "attributes": {
      "drupal_internal__id": 1,
      "drupal_internal__revision_id": 6,
      "langcode": "en",
      "revision_created": "2025-06-06T20:35:40+00:00",
      "revision_log_message": null,
      "name": "2025 Crop Plan",
      "status": "active",
      "created": "2025-06-05T14:47:23+00:00",
      "changed": "2025-06-06T20:35:40+00:00",
      "archived": null,
      "default_langcode": true,
      "revision_translation_affected": true,
      "comment": {
        "status": 2,
        "cid": 0,
        "last_comment_timestamp": 1749134843,
        "last_comment_name": null,
        "last_comment_uid": 1,
        "comment_count": 0
      },
      "data": null,
      "notes": null,
      "flag": []
    },
    "relationships": {
      "plan_type": {
        "data": {
          "type": "plan_type--plan_type",
          "id": "1de45b9b-f540-408b-99bc-d1cb877b7c77",
          "meta": {
            "drupal_internal__target_id": "crop"
          }
        },
        "links": {
          "related": {
            "href": "http://axilab.ecn.purdue.edu/api/plan/crop/fe394bee-07c1-4fb7-b4ea-46b673d9a283/plan_type?resourceVersion=id%3A6"
          },
          "self": {
            "href": "http://axilab.ecn.purdue.edu/api/plan/crop/fe394bee-07c1-4fb7-b4ea-46b673d9a283/relationships/plan_type?resourceVersion=id%3A6"
          }
        }
      },
      "revision_user": {
        "data": {
          "type": "user--user",
          "id": "00c94817-cfca-45f8-92b0-e50af7f631ff",
          "meta": {
            "drupal_internal__target_id": 2
          }
        },
        "links": {
          "related": {
            "href": "http://axilab.ecn.purdue.edu/api/plan/crop/fe394bee-07c1-4fb7-b4ea-46b673d9a283/revision_user?resourceVersion=id%3A6"
          },
          "self": {
            "href": "http://axilab.ecn.purdue.edu/api/plan/crop/fe394bee-07c1-4fb7-b4ea-46b673d9a283/relationships/revision_user?resourceVersion=id%3A6"
          }
        }
      },
      "uid": {
        "data": {
          "type": "user--user",
          "id": "6cd48be4-de3d-4557-aea5-dbce39ec2520",
          "meta": {
            "drupal_internal__target_id": 1
          }
        },
        "links": {
          "related": {
            "href": "http://axilab.ecn.purdue.edu/api/plan/crop/fe394bee-07c1-4fb7-b4ea-46b673d9a283/uid?resourceVersion=id%3A6"
          },
          "self": {
            "href": "http://axilab.ecn.purdue.edu/api/plan/crop/fe394bee-07c1-4fb7-b4ea-46b673d9a283/relationships/uid?resourceVersion=id%3A6"
          }
        }
      },
      "file": {
        "data": [],
        "links": {
          "related": {
            "href": "http://axilab.ecn.purdue.edu/api/plan/crop/fe394bee-07c1-4fb7-b4ea-46b673d9a283/file?resourceVersion=id%3A6"
          },
          "self": {
            "href": "http://axilab.ecn.purdue.edu/api/plan/crop/fe394bee-07c1-4fb7-b4ea-46b673d9a283/relationships/file?resourceVersion=id%3A6"
          }
        }
      },
      "image": {
        "data": [],
        "links": {
          "related": {
            "href": "http://axilab.ecn.purdue.edu/api/plan/crop/fe394bee-07c1-4fb7-b4ea-46b673d9a283/image?resourceVersion=id%3A6"
          },
          "self": {
            "href": "http://axilab.ecn.purdue.edu/api/plan/crop/fe394bee-07c1-4fb7-b4ea-46b673d9a283/relationships/image?resourceVersion=id%3A6"
          }
        }
      },
      "asset": {
        "data": [],
        "links": {
          "related": {
            "href": "http://axilab.ecn.purdue.edu/api/plan/crop/fe394bee-07c1-4fb7-b4ea-46b673d9a283/asset?resourceVersion=id%3A6"
          },
          "self": {
            "href": "http://axilab.ecn.purdue.edu/api/plan/crop/fe394bee-07c1-4fb7-b4ea-46b673d9a283/relationships/asset?resourceVersion=id%3A6"
          }
        }
      },
      "log": {
        "data": [],
        "links": {
          "related": {
            "href": "http://axilab.ecn.purdue.edu/api/plan/crop/fe394bee-07c1-4fb7-b4ea-46b673d9a283/log?resourceVersion=id%3A6"
          },
          "self": {
            "href": "http://axilab.ecn.purdue.edu/api/plan/crop/fe394bee-07c1-4fb7-b4ea-46b673d9a283/relationships/log?resourceVersion=id%3A6"
          }
        }
      },
      "season": {
        "data": [
          {
            "type": "taxonomy_term--season",
            "id": "477d62d6-8934-47f6-9c85-80453909c293",
            "meta": {
              "drupal_internal__target_id": 111
            }
          }
        ],
        "links": {
          "related": {
            "href": "http://axilab.ecn.purdue.edu/api/plan/crop/fe394bee-07c1-4fb7-b4ea-46b673d9a283/season?resourceVersion=id%3A6"
          },
          "self": {
            "href": "http://axilab.ecn.purdue.edu/api/plan/crop/fe394bee-07c1-4fb7-b4ea-46b673d9a283/relationships/season?resourceVersion=id%3A6"
          }
        }
      }
    }
  },
  "links": {
    "self": {
      "href": "http://axilab.ecn.purdue.edu/api/plan/crop/fe394bee-07c1-4fb7-b4ea-46b673d9a283?resourceVersion=id%3A6"
    }
  }
}

I was expecting there would be plant assets in the relationship. I am not sure if I missed something. Does anyone have any suggestions?

2 Likes

Hi @tbureete - welcome to the forum! :smiley:

Great question. The crop plan models things a bit differently than a “default” plan entity. Instead of referencing plant assets via the assets relationship directly on the plan entity, it uses an “in between” entity type called a plan_record which references both the plan and the plant to connect them together. So the plan doesn’t contain any references itself.

The benefit of doing this is we can add additional metadata to the plan_record entity. That’s where we store seeding_date, transplant_days, and maturity_days, 'harvest_days` for each plant asset relationship.

In the case of crop plans, the plan_record entity bundle (aka sub-type) is crop_planting (in the same way other entity types work: crop_planting is to plan_record as crop is to plan or plant is to asset).

You should be able to get a list of all the plan_record entities associated with a plan using the following API endpoint, using the plan UUID:

api/plan_record/crop_planting?filter[plan.id]=bd67af73-ea62-46ec-b23c-a6dbc765a94b

or using the integer ID of the plan:

/api/plan_record/crop_planting?filter[plan.drupal_internal__id]=1

Hope that helps!

1 Like

Worth noting: we will probably remove the asset and log relationships from crop plans in the future. Those get added to all plan types by default, but can be disabled on a per-plan-type basis. Since they are not being used for crop plans, they should be disabled IMO, but that was missed during development (the module is still in alpha, after all). :slight_smile:

Also notes: @ktohalloran discovered a possible bug with POSTing new plan_record entities, so that may not be working currently. See this issue:

If you can test to confirm that, I can help put together a fix ASAP.

1 Like

Hi Mike,

Thank you for your suggestion. From testing, I can GET data from both plan and plan_record. However, as you suspected, the POST request to plan_record did not work (but it worked for plan). If you have bandwidth to investigate this issue, it would be great.

Best,
Tam

1 Like

@tbureete Thanks for confirming! @paul121 started working on a fix for that here: Comparing farmOS:4.x...paul121:3.x-plan-record-access · farmOS/farmOS · GitHub

We’ll try to get that finished up and included in the next release. But in the meantime maybe we can find a way to unblock you…

Q: How are you hosting farmOS currently? Depending on your setup I might be able to walk you through applying a temporary patch to fix the issue in your instance.

1 Like

Hi Mike,

Currently, I am running on docker with tag 3.x-dev. I pulled in image 6 weeks ago, so it is not the latest version. I don’t have any restrictions to stay with any specific version. So, I will be happy to upgrade or apply patches.

Best,
Tam

1 Like

@tbureete OK so maybe the first thing to try is replacing this file in your codebase: farmOS/modules/core/plan/src/Access/PlanRecordAccess.php at 1375cfca335375434c6a07abafb8b7f5cb8a1916 · paul121/farmOS · GitHub

If you set up farmOS as a local development environment (via the instructions here) then you should have that file in your host filesystem (mounted into the Docker container as a volume under /opt/drupal).

In your local www directory (which is the volume), navigate to www/web/profiles/farm/modules/core/plan/src/Access/ and edit the PlanRecordAccess.php file. Replace its contents with the version I linked above (which is from @paul121’s branch that attempts to fix the issue).

I’m not sure if you need to clear the Drupal cache after making the change, but always worth a try. :slight_smile:

Make a backup of the original file first in case that breaks anything (you can also find the original in GitHub). You’ll be the first person to test this, so hopefully it works! Please let us know - and we can start getting a pull request together to get it fixed upstream.